Closing an XML file after reading so it can be deleted - vb.net

I have a problem deleting an XML file after loading it into .XMLDocument.
My code parses the XML file for specific nodes and allocates their values to variables.
Once complete the code processes data based on the values from the XML file.
This works fine until the end when i try to delete the XML file as it is still open and i then get a error "The process cannot access the file because it is being used by another process" which i guess is the XMLDocument reader.
Here is a section of the the XML processing code - this works fine.
`Dim xmlDoc As XmlDocument = New XmlDocument()
xmlDoc.Load(strFileName)
intPassed = xmlDoc.SelectSingleNode("//CalibrationPassed").InnerText
boolCheck = xmlDoc.SelectSingleNode("//ChecksComplete").InnerText
intCertRequired = xmlDoc.SelectSingleNode("//Schedule").InnerText
Console.WriteLine("Calibration Passed: " & intPassed)
Console.WriteLine("Checks Complete:" & boolCheck)
Console.WriteLine("Schedule: " & intCertRequired)
strFirstName = xmlDoc.SelectSingleNode("//FirstName").InnerText
strEMail = xmlDoc.SelectSingleNode("//Email").InnerText
strCusEmail = xmlDoc.SelectSingleNode("//CustomerEmail").InnerText
strCompanyName = xmlDoc.SelectSingleNode("//CompanyName").InnerText
strContractNumber = xmlDoc.SelectSingleNode("//ContractNo").InnerText
Console.WriteLine("First name: " & strFirstName)
Console.WriteLine("Email: " & strEMail)
Console.WriteLine("Customer EMail: " & strCusEmail)
Console.WriteLine("Company name: " & strCompanyName)
Console.WriteLine("Contract no: " & strContractNumber)
Console.WriteLine("XML Parsing Complete")
`
The code being used to delete the file is:
If System.IO.File.Exists(strFileName) = True Then
System.IO.File.Delete(strFileName)
Console.WriteLine("Deleted XML file")
End If
Any help on where I'm going wrong would be great-fully received.
Thanks

XmlDocument.Load uses a stream reader under the hood. There are two strategies for avoiding this:
1) A Using block will close/dispose your stream automatically and promptly
Using xmlDoc As XmlDocument = New XmlDocument()
xmlDoc.Load(strFileName)
'all of your copying stuff
End Using
'now delete your file
2) Load your XML and avoid using a reader:
Dim strXml as string
strXml = System.IO.File.ReadAllText(strFileName)
Dim xmlDoc As XmlDocument = New XmlDocument()
xmlDoc.LoadXml(strXml)
'and then the rest of your code
The downside to the 2nd approach is that my example doesn't consider any other encoding, but it should get you past your current problem. Dealing with various encoding options is a whole different matter.

If you're not using an xmlreader, then try this:
Dim xmlDoc = New XmlDocument()
doc.Load(strFileName)
//do all the reading stuff
Using writer = New StreamWriter(strFileName)
xmlDoc.Save(writer)
End Using
It will save your xmlDoc (in an attempt at disposing) then it should have unlocked the document which can then be deleted.
I haven't tested the code but give it a go

Thanks for all the help, it was being held open by streamreader which i had not considered to be a cause of the problem as I assumed it would have caused an error when XMLDocument used the file.

This worked for me. Setting the reference to nothing (null) to force a garbage collection.
xmlDoc = Nothing

Related

delete Sharepoint file using Script Task

I need to delete a Sharepoint file using the Script Task from SSIS. In Visual Basic, I've tried using the SPListItemCollection with imports Microsoft.Sharepoint but it doesn't recognize the namespace. I didn't find lots of threads on this subject or what I've found wasn't related with script task, so any help will be really appreciated. Many thanks
Update based on #Hadi answer
Thanks Hadi for your answer. I've given up the idea of using SPListCollection as it seems too complicated. Instead I'm trying to delete the file after it is downloaded from Sharepoint to the local folder. I would need help at the line that actually deletes the file. Here is the code:
Public Sub Main()
Try
' get location of local folder
Dim dir As DirectoryInfo = New DirectoryInfo(Dts.Variables("DestP").Value.ToString())
If dir.Exists Then
' Create the filename for local storage
Dim file As FileInfo = New FileInfo(dir.FullName & "\" & Dts.Variables("FileName").Value.ToString())
If Not file.Exists Then
' get the path of the file to download
Dim fileUrl As String = Dts.Variables("SHP_URL").Value.ToString()
If fileUrl.Length <> 0 Then
Dim client As New WebClient()
If Left(fileUrl, 4).ToLower() = "http" Then
'download the file from SharePoint
client.Credentials = New System.Net.NetworkCredential(Dts.Variables("$Project::UserN").Value.ToString(), Dts.Variables("$Project::Passw").Value.ToString())
client.DownloadFile(fileUrl.ToString() & "/" & Dts.Variables("FileName").Value.ToString(), file.FullName)
Else
System.IO.File.Copy(fileUrl.ToString() & Dts.Variables("FileName").Value.ToString(), file.FullName)
End If
'delete file from Sharepoint
client.(fileUrl.ToString() & "/" & Dts.Variables("FileName").Value.ToString(), file.FullName).delete()
Else
Throw New ApplicationException("EncodedAbsUrl variable does not contain a value!")
End If
End If
Else
Throw New ApplicationException("No ImportFolder!")
End If
Catch ex As Exception
Dts.Events.FireError(0, String.Empty, ex.Message, String.Empty, 0)
Dts.TaskResult = ScriptResults.Failure
End Try
Dts.TaskResult = ScriptResults.Success
End Sub
Update 1 - Delete using FtpWebRequest
You cannot delete file using WebClient class. You can do that using FtpWebRequest class. And send a WebRequestMethods.Ftp.DeleteFile request as mentioned in the link below:
How To Delete a File From FTP Server in C#
It should work with Sharepoint also.
Here is the function in VB.NET
Private Function DeleteFile(ByVal fileName As String) As String
Dim request As FtpWebRequest = CType(WebRequest.Create(fileUrl.ToString() & "/" & fileName), FtpWebRequest)
request.Method = WebRequestMethods.Ftp.DeleteFile
request.Credentials = New NetworkCredential(Dts.Variables("$Project::UserN").Value.ToString(), Dts.Variables("$Project::Passw").Value.ToString())
Using response As FtpWebResponse = CType(request.GetResponse(), FtpWebResponse)
Return response.StatusDescription
End Using
End Function
You should replace the following line:
client.(fileUrl.ToString() & "/" & Dts.Variables("FileName").Value.ToString(), file.FullName).delete()
With
DeleteFile(Dts.Variables("FileName").Value.ToString())
Also you may use the following credentials:
request.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
References
How to pass credentials to httpwebrequest for accessing SharePoint Library
How To Delete a File From FTP Server in C#
Downloading all files in a FTP folder and then deleting them
Deleting file from FTP in C#
How To Delete a File From FTP Server in C#
Initial Answer
I was searching for a similar issue from a while, it looks like you cannot delete a Sharepoint file in SSIS using a File System Task or Execute Process Task, the only way is using a Script Task. There are many links online describing this process such as:
how to delete or remove only text files from share point in C# or SSIS script?
Fastest way to delete all items with C#
Deleting files programatically
Deleting all the items from a large list in SharePoint
Concerning the problem that you have mentioned, i think you should make sure that Microsoft.Sharepoint.dll is added as a reference inside the Script Task. If so try using Microsoft.Sharepoint.SPListItemCollection instead of SPListItemCollection.
Thanks #Hadi for your help.
For me it didn't work with FTPWebResponse.
It worked with HttpWebRequest. Here is the script:
Dim request As System.Net.HttpWebRequest = CType(WebRequest.Create(fileUrl.ToString() & "/" & Dts.Variables("FileName").Value.ToString()), HttpWebRequest)
request.Credentials = New System.Net.NetworkCredential(Dts.Variables("$Project::UserN").Value.ToString(), Dts.Variables("$Project::Passw").Value.ToString())
request.Method = "DELETE"
Dim response As System.Net.HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)

Strange symbols stopping my batch file running in VB.net

I am trying to create and run a batch file from VB.net, then get the output and print it out. But when it runs it is appended by these symbols '´╗┐. Causing this error '´╗┐cd' is not recognized as an internal or external command, operable program or batch file. When I look at the batch file in notepad++ there is no symbol there! What is happening! Thanks James.
Code:
Dim path As String = Directory.GetCurrentDirectory()
Dim command As String = "cd " & path & " & " & argument
MsgBox(command)
Dim file As System.IO.StreamWriter
file = My.Computer.FileSystem.OpenTextFileWriter(tempFile, False)
file.WriteLine("#ECHO OFF")
file.WriteLine(command)
file.Close()
Dim objProcess As New Process()
Dim SROutput As System.IO.StreamReader
With objProcess.StartInfo
.FileName = tempFile
.RedirectStandardOutput = True
.UseShellExecute = False
.Arguments = ""
End With
objProcess.Start()
SROutput = objProcess.StandardOutput
Do While SROutput.Peek <> -1
'MessageBox.Show(SROutput.ReadLine)
rtbOutput.Text = rtbOutput.Text & SROutput.ReadLine & vbNewLine
Loop
objProcess.Dispose()
'Process.Start(tempFile)
rtbOutput.Text = rtbOutput.Text & message & vbNewLine
That's a Byte Order Mark.
It means the OpenTextFileWriter() method is using a different encoding than you expect. You can fix the problem by using OpenTextFileWriter() overload that allows you pick an encoding like ASCII with no byte order mark or use the encoding with the byte order mark that matches what the DOS subsystem is expecting.
Solved, Im not entirely sure what was happening when it was writing the file, but I have changed it to this
Using writer As StreamWriter = New StreamWriter(tempFile)
writer.Write(command)
End Using
and its now running fine!. Thanks for any time spent on this and feel free to post an explination as to why this was happening.

GZipstream cuts off data from original file when decompressing

For a long time I have been trying to debug why my parsing counts were off when downloading files to be parsed and been made to look really dumb about this. I did some debugging and found that the file I download when trying to decompress using GZipStream shows that it misses data from the original file. Here is my code for decompressing:
Using originalFileStream As FileStream = fileItem.OpenRead()
Dim currentFileName As String = fileItem.FullName
Dim newFileName = currentFileName.Remove(currentFileName.Length - fileItem.Extension.Length)
newFile = newFileName
Using decompressedFileStream As FileStream = File.Create(newFileName)
Using decompressionStream As GZipStream = New GZipStream(originalFileStream, CompressionMode.Decompress)
decompressionStream.CopyTo(decompressedFileStream)
Console.WriteLine("Decompressed: {0}", fileItem.Name)
decompressionStream.Close()
originalFileStream.Close()
End Using
End Using
End Using
Now what I do is return the newfile to the calling function and read the contents from there:
Dim responseData As String = inputFile.ReadToEnd
Now pasting the url in the browser and downloading from there and then opening using winrar I can see the data is not the same. Now this does not happen all the time as some files parse and decompress correctly. Each downloaded file has check counter to compare how many posts I am supposed to be parsing from it and that triggered me to see the mismatch in counts.
EDIT
Here is what I found in addition. If I read the problem file (as I said that only some files happen this way) by individual lines I will get all the data:
Dim rData As String = inputFile.ReadLine
If Not rData = "" Then
While Not inputFile.EndOfStream
rData = inputFile.ReadLine + vbNewLine + rData
End While
getIndividualPosts(rData)
End If
Now if I try to read an individual line from a file that is not problematic it will return nothing and so I will have to readtoEnd. Can anyone explain this odd behavior and is it related to the GZIPSTREAM or some error in my code.

Illegal Characters in Path Error When Downloading CSV File

I need download a CSV file and then read it. Here is my code:
tickerValue = "goog"
Dim strURL As String = "http://ichart.yahoo.com/table.csv?s=" & tickerValue
Dim strBuffer As String = RequestWebData(strURL)
Using streamReader = New StreamReader(strBuffer)
Using reader = New CsvReader(streamReader)
I keep getting this error: An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll Additional information: Illegal characters in path.
What am I doing wrong?
Additional Info
In another part of my program I use this code and it works fine.
Address = http://www.nasdaq.com/screening/companies-by-industry.aspx?exchange=AMEX&render=download
Dim strBuffer As String = Historical_Stock_Prices.RequestWebData(Address)
Using streamReader = New StringReader(strBuffer)
Using reader = New CsvReader(streamReader)
Isn't my second code the same concept as my problem code?
you are giving it, essentially, a web url. somewhere in your code, it does not support the web url. it could be the streamreader. it could be the CsvReader.
what line of code does this point to?
the best bet is to save the file TO DISK, then read from disk.
UPDATE
here is an example to SAVE to disk:
using writer as new StreamWriter("C:\Test.csv")
writer.Write(strBuffer)
writer.Close()
end using
here is an example to READ from disk:
using strReader as new StreamReader("C:\Test.csv")
' this code is presumably how it works for reading into the CsvReader:
using reader as new CsvReader(strReader)
' now do your thing
end using
strReader.Close()
end using

My visual basic program is creating files improperly and they won't run correctly through other programs

I have a visual basic program that creates files that are necessary for a semiweekly process. These files are a .bas file (for qbasic) and a .lot file (for voxco automation). I can live without the .bas file and simply put it's functionality directly into my program. I do, however, need the .lot file. Normally these files are copied from old files and edited manually. This is, as you can imagine, tedious. However, the files created by my program do not run properly through any means I have of running them. When I compare the manually created files to the automatically created files, the differences are minimal to nonexistent. The encoding doesn't seem to be an issue either. I simply don't know why the files created by my program are not running properly when the files created manually are working fine.
Here is the code that creates the .lot file:
Dim LotText As String
LotText = *removed*
Dim QuLines As String = Nothing
Dim Reader As New StreamReader(LotFilePath & OldStudy & ".LOT")
Dim SLine As String = Nothing
While Not Reader.EndOfStream
SLine = Reader.ReadLine()
If SLine.StartsWith("*QU") Then
QuLines = QuLines & SLine & vbCrLf
End If
End While
LotText = LotText & QuLines
Dim TempPath As String
TempPath = LotFilePath & "BackEnd\" & StudyID & ".LOT"
My.Computer.FileSystem.WriteAllText(TempPath, LotText, 0)
When you say the differences are minimal - what are they exactly!? A single character at the beginning of the file could be making the whole thing fail.
I have had problems in the past with writing vbCrLf to files in this manner; try the following code instead to see if it offers any improvement.
Dim LotText As String = *removed*
' Create a list of strings for the output data
Dim QuLines As New Collections.Generic.List(Of String)
Dim Reader As New StreamReader(Path.Combine(LotFilePath, OldStudy & ".LOT"))
Dim SLine As String = Nothing
While Not Reader.EndOfStream
SLine = Reader.ReadLine()
If SLine.StartsWith("*QU") Then
' This line is desired; add it to our output list
QuLines.Add(SLine)
End If
End While
' Concatenate the existing data and the output; uses the system defined NewLine
LotText &= Environment.NewLine & String.Join(Environment.Newline, QuLines)
Dim TempPath As String = Path.Combine(LotFilePath, "BackEnd", StudyID & ".LOT")
My.Computer.FileSystem.WriteAllText(TempPath, LotText, 0)