Using sr As New System.IO.StreamWriter("C:\test.txt")
sr.WriteEnd
End Using
Using sr As New System.IO.StreamReader("C:\test.txt")
sr.ReadToEnd
End Using
This is equivalent to:
sr = New System.IO.StreamWriter("C:\test.txt")
sr.WriteEnd
sr.Dispose
sr = New System.IO.StreamReader("C:\test.txt")
sr.ReadToEnd
sr.Dispose
Am I right in saying the attempt to read the file may fail if the Garbage collector had not got around to disposing the StreamWriter and closing the file. If so where is the benefit is using the Using Statement in this case. Is is better practice to use
Using sr As New System.IO.StreamWriter("C:\test.txt")
sr.WriteEnd
sr.close()
End Using
It is a best practice to always the Using statement because if an exception is thrown during the reading the stream might never be disposed and your application will leak a file handle. If this is a desktop application the process will probably die and release the handle but in a web application not releasing unmanaged resources such as file handles could be catastrophic.
Also you don't need to call Close on your stream if you are calling Dispose.
Remark: if you want to read the contents of a text file into a string you could directly do this instead of going through the pain of instantiating a StreamReader, reading it to the end and disposing it:
Dim data = File.ReadAllText("C:\test.txt");
No, the Garbage Collector does not dispose the object, calling Dispose does that, and the using block makes sure that happens. The object may still be in memory, but the file will have been dealt with.
If you didn't call close or dispose (either manually or by use of the using block), and the object got collected it would then be finalised (slowing up garbage collection) and that would close the file handle. But this last-chance is different to dispose.
You don't have to call close on the file within the using block, but you are free to. This may be a good idea to release the handle quickly (not often an issue with file handles, more often an issue with pooled database connections), with the using block giving you an added guarantee (it's always safe to call dispose, even if its already been called).
Actually, it is equivalent to this: The Finally blocks will guarantee the Dispose is called and everything is cleaned up in the event of an exception.
Try
sr = New System.IO.StreamWriter("C:\test.txt")
sr.WriteEnd()
Finally
sr.Dispose()
End Try
Try
sr = New System.IO.StreamReader("C:\test.txt")
sr.ReadToEnd()
Finally
sr.Dispose()
End Try
Think if you are done and don't care too much about it after, can let the dispose just happen
BUT dispose may take a while, so if you need to use the file (e.g. pass to another app, move to new location, or any other use of the file), then probably should Close it explicitly
Close should release any locks, expect this will fail:
dim fn as string = "C:\temp.txt"
Using sr As New System.IO.StreamWriter(fn)
sr.WriteLine("Junk")
' sr.close
End Using
system.io.file.delete(fn)
Expect the delete to throw an error, since file dispose may not yet have happened
If you explicitly close (e.g. un-comment the close), then should always succeed
Related
It is a very basic code that I'm using for my college coursework. Unfortunately, we're only allowed to use StreamRead and StreamWrite type functions for marking reasons. I'm unsure as to how to basically rewrite the line already in the file with a new value. I know I could delete the file and recreate but we also get marked down for that sort of thing. Any ideas?
Private Function WriteTaxableIncome()
Dim TaxableIncomeStreamWriter As IO.StreamWriter
TaxableIncomeStreamWriter = New IO.StreamWriter("C:\Computing\Coursework\TaxableIncome.txt", True)
TaxableIncomeStreamWriter.WriteLine(TaxableIncome)
TaxableIncomeStreamWriter.Close()
End Function
When you create the StreamWriter instance, you have called the constructor with New (path As String, append As Boolean), and passed True into the append argument, so that will make the writer append to the file, instead of overwrite it. Seems like the exact opposite of what you want to do. Instead, pass False. Also, use a Using block which will Open and Close the writer. It automatically calls Dispose so you can be sure no part of it is left open.
Using writer As New IO.StreamWriter("C:\Computing\Coursework\TaxableIncome.txt", False)
writer.WriteLine(TaxableIncome)
End Using
Yes, I realize Garbage Collector takes care of freeing up memory, and I also know of the inefficiencies in clearing up memory manually, however for educational purposes I would like to know how to dispose a class instance in VB.Net.
look at the example given in MSDN: http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
to use it, you can either use Using block or call Dispose() directly. for example:
' use Using Block:
Using r = New MyResource(100)
Console.WriteLine(r.ToString())
End Using
' call Dispose directly:
Dim r = New MyResource(100)
Console.WriteLine(r.ToString())
r.Dispose()
I'm wondering if this is a good way of doing data access, in terms of all the database objects being properly closed and disposed? For example:
Using conn As New SqlConnection(MyConnectionString)
Using cmd As New SqlCommand("some SQL here", conn)
... add parameters ...
conn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader()
While dr.Read()
... do stuff ...
Wend
End Using
End Using
End Using
Is nesting Using like acceptable practice? If I exit the method at some point within the Read() loop, will the use of Using like this ensure all objects are cleaned up properly regardless?
Using guarantees orderly disposal in an implicit try/finally block.
' THE FOLLOWING TRY CONSTRUCTION IS EQUIVALENT TO THE USING BLOCK
Dim resource As New resourceType
Try
' Insert code to work with resource.
Catch ex As Exception
' Insert code to process exception.
Finally
' Insert code to do additional processing before disposing of resource.
resource.Dispose()
End Try
Nested usings work in a similar fashion. If you exit a block of code, it will execute the finally block, and properly dispose your objects.
http://msdn.microsoft.com/en-US/library/htd05whh(v=VS.80).aspx
To add, the Using block will "behind the scenes" add a Try Finally statement. In the finally statement it will call IDisposable.Dispose on the object. In other words, no matter what you do or what happens, the object will get disposed.
Yes, this is ok. The Dispose method of IDisposable objects is always called.
PS: In this case, the Dispose method also contains the Close method.
You are writing VB.Net, so this only partially applies, but for the C# folks out there using StyleCop, multiple using statements like this will cause exception 2202 in StyleCop.
There is a lengthy section at the msdn link of dissenting comments as to the usefulness of this rule in stylecop.
I will not make a judgment call as to whether you should heed StyleCops warnings for C# in your VB.Net code.
I have been creating multiple background threads to parse xml files and recreate new xml files. Now the problem I am having is that even though I use synclock on global variables, I will still at times get errors and I am sure that this is just the crude way of coding I am doing, but I was wondering if someone had a better option.
program flow =
access local folder and upload all files into list
strip each file into xml entries and put these entries into an arraylist
parse for specific values and enter these values into a database table
now create a thread and take the arraylist of entries and the thread will reparse
thread parses and creates a new xml file
main thread continues with another function and then goes and get a file from list
I will add some code to show problem areas but if I have declared global variable in use does the different threads overwrite that value in the variable causing contamination.
For Each g In resultsList
gXmlList.Add(g)
Next
Dim bgw As New BackgroundWorker
bgw.WorkerSupportsCancellation = True
AddHandler bgw.DoWork, New DoWorkEventHandler(AddressOf createXML)
AddHandler bgw.RunWorkerCompleted, AddressOf WorkComplete
threadlist.Add(bgw)
bgw.RunWorkerAsync()
Private Sub createXML()
num += 1
Dim file As String = Module1.infile
xmlfile = directoryPath & "\New" & dateTime.Now.ToUniversalTime.ToString("yyyyMMddhhmmss") & endExtension
Thread.Sleep(2000)
Dim doc As XmlDocument = New XmlDocument
**xwriter = New XmlTextWriter(xmlfile, Encoding.UTF8)** this is where ioexception error
xwriter.Formatting = Formatting.Indented
xwriter.Indentation = 2
xwriter.WriteStartDocument(True)
xwriter.WriteStartElement("Posts")
I have global variables through out the app and should I be locking each one and does this not make using threads then useless.
Dim j As Integer = 0
I believe your biggest problem is not knowing what features in .Net are thread safe. A list for example is not (a dictionary is). While you may get away with it you will eventually run into problems with locking, etc.
Your using classes and variables that are not thread safe. Any time you are working with threads you have to be Extremely careful with locking. To answer your question, yes, you have to lock and unlock everything you are working with unless the type / method specifically handles it for you.
There are a lot of multi threading (PLINQ for example) in .Net 4.0 which handle a lot of the "grunt work" for you. While you should learn and understand how to do thread safe code yourself it will give you a head start.
Try passing the data into the createXML() method. That may help isolate the code from other data being accessed. I would suggest reading up on threading and learning how to do it without a background worker.
Global variables are generally a bad idea. Given your VB code I'm guessing this is a carry over from the VB6 world for you. That's not in any way intended to be insulting, just trying to help advance your skills forward. Variable scope should be as confined as possible.
Another thought looking at your code is to learn how to use String.Format() when building strings / paths.
Simple manual thread in VB to get you started:
Dim bThread As New Threading.Thread(AddressOf createXML)
bThread.IsBackground = True
bThread.Start()
Well if you are having issues with thread locking then you can simply wrap your action in the following manor.
'This will need to be out of scope so that all threads have access to it
Dim readerWriterLock As New Threading.ReaderWriterLockSlim
readerWriterLock.EnterWriteLock()
xwriter = New XmlTextWriter(xmlfile, Encoding.UTF8)
'other logic
readerWriterLock.ExitWriteLock()
'anything reading from this would need to have the following
readerWriterLock.EnterReadLock()
'logic
readerWriterLock.ExitReadLock()
Try this and then if not successful post the exception message and any other information that you can.
I recently wrote a section of code wherein upon finishing, I received a warning from the compiler telling me that one of my variables is being used before it is assigned a value. In practice, the method call on this object will never be made without the object being instantiated beforehand. Here is the snippet of code
Try
fs = New FileStream(fileName, FileMode.Open)
Dim PolarMatrix As PolarMatrix
PolarMatrix = DirectCast(bf.Deserialize(fs), PolarMatrix)
fs.Close()
Return TypeOfStructure.Polar
Catch ex As Exception
fs.Close() 'Warning on this line: Variable 'fs' is used before it has been assinged a value
End Try
I assume I'm receiving this warning because the first line in the Try section may be the line to throw the error, and the Object will never be instantiated. FileName though, is a variable being passed to this method which has already been checked for errors, so it is guaranteed to be correct. The error I'm expecting to perhaps be thrown comes during the deserialization.
So my question: When warnings are given on objects that the compiler thinks may not have been instantiated, does this overrule the user knowing that a problem will never arise on that line? Is it sometimes necessary to add code simply to appease the compiler? Or is what I've done here bad practice?
How are you sure that fs will always be instantiated, even if the filename is correct, it could still fail to open for many other reasons.
However, the easy solution to this problem would be to get rid of the catch completely and use a Using statement instead, as:
Try
Using fs = New FileStream(fileName, FileMode.Open)
Dim PolarMatrix As PolarMatrix
PolarMatrix = DirectCast(bf.Deserialize(fs), PolarMatrix)
Return TypeOfStructure.Polar
End Using
Catch ex as Exception
' do something here
End Try
This means that the fs will be automatically disposed of when this section of code exists, and Stream.Dispose closes the stream.
And to answer your actual question, sometimes the compiler is wrong, and you will have to either ignore the warnings or add some extra code to make them go away, but in general, assume that the compiler is correct until you're absolutely sure that that's not the case.