How to Copy a file without locking it? - vb.net

I have a large log file located on a network drive that is being constantly written to. How can I copy it through code without locking it?
Try
Microsoft.VisualBasic.FileSystem.FileCopy("sourcefile", "destinationfile")
Catch ex As Exception
' Handle Error
End Try
The code above, unfortunately does not work well, because while its copying the file, nothing can be written to that file.
Edit 1:
It was suggested to read the content of the file and write it to the output. I would prefer not to do this, because the file is several gigabytes. I reserve this option only as a last resort, only if there is no other way to copy the file without locking it and without readying the content.

how about using FileOpen in shared mode and reading and writing the output file yourself
FileOpen(1, "SourceFile", OpenMode.Input, OpenAccess.Default, OpenShare.Shared)
// open destination file here read and while not at end of sourcefile read it // and write blocks out to destinatioon file.
FileClose(1)

If you can't copy the file to work on it, or don't want to open the file in shared mode and then copy it that way, then another option is to have the system that generates the log file generate a series of smaller log files. Maybe one per unit, or production run, or hour, or day, or some other arbitrary break point.

Related

Either correct VB6/DOS/SQL function or suggest better alternative

I am currently reprogramming code made long ago by a less than skilled programmer. Granted the code works, and has for a number of years but it is not very efficient.
The code in question is in VB6 with SQL calls and it checks a particular directory on the drive (in this example we will use c:\files) and if a file exists, it moves the file to the processing directory loads the parameters for that particular file and processes them accordingly.
Currently the code uses the DIR function in VB6 to identify a file in the appropriate directory. The only problem is that if a number of files exist in the directory it is a crap shoot as to if it will grab the 5kb file and process it in 3 seconds or if it will grab the 500,000kb file and not process any others for the next 10 minutes.
I search many message boards to find some way to have it pick the smallest file and found I could build a complicated array to perform something similar to a sort but I decided to try alternate ideas instead to hopefully reduce processing time involved. Using ancient DOS knowledge I created something that should work, but for some reason is not (hence posting here).
I made a batch file that we will call c:\test.bat which contained the following lines:
delete c:\test.txt
dir /OS /B c:\files\*.txt>c:\test.txt
This deletes a prior existence of test.txt the pipes a directory without headers sorted by file size smallest to largest into c:\test.txt.
I then inserted the following code into the pre-existing code at the beginning:
Shell "c:\test.bat", vbHide
filepath = "c:\test.txt"
Open filepath For Input As #1
Input #1, filegrabber
Close #1
When I step through the code I can see that this works correctly, except now later on in the code I get a
Runtime error 91 Object variable or with block variable not set
in regard to assigning a FileSystemObject. Am I correct in guessing that FSO and Shell do not work well together? Also if you can suggest a better alternative to getting the smallest file from a existing directory suggestions are appreciated.
No need for sorting.
Just use Dir() to cruise through the directory. Before the loop set a Smallest Long variable to &H7FFFFFFF then inside the loop test each returned file name using the FileLen() function.
If FileLen() returns a value less than Smallest assign that size to Smallest and assign that file name to SmallestFile a String variable.
Upon loop exit if Smallest = &H7FFFFFFF there were no files, otherwise SmallestFile has your file name.
Seems incredibly simple, what am I missing?
Another approach is to use the FileSystemObject's Files collection. Just iterate the files collection for a given folder and evaluate each File object's Size property. So long as you don't have a million files in a folder or something, performance should be fine.

Using the same file error

On a button click I have the following code to write what Is in my textboxes.
Dim file As System.IO.StreamWriter
file = My.Computer.FileSystem.OpenTextFileWriter("C:/Users/Nick/Documents/Dra.txt", False)
file.WriteLine(NameBasic)
file.WriteLine(LastBasic)
file.WriteLine(PhoneBasic)
file.WriteLine(NameEmer1)
On my form load, I load what is in the notepad from what was written, It is saying It is already being used(the file) which is true, how can I have two different functions(write, and read) manipulating the same file with out this error?
The process cannot access the file 'C:\Users\Nick\Documents\Dra.txt' because it is being used by another process.
And here is the code for my onformload
Dim read As System.IO.StreamReader
read = My.Computer.FileSystem.OpenTextFileReader("C:/Users/Nick/Documents/Dra.txt")
lblNameBasic.Text = read.ReadLine
I am sort of stuck on this problem, thank you
You need to close the file when you are done writing to it.
Dim file As System.IO.StreamWriter
file = My.Computer.FileSystem.OpenTextFileWriter("C:/Users/Nick/Documents/Dra.txt", False)
file.WriteLine(NameBasic)
file.WriteLine(LastBasic)
file.WriteLine(PhoneBasic)
file.WriteLine(NameEmer1)
file.Close()
To answer your question:
how can I have two different functions(write, and read) manipulating the same file with out this error?
If you really want to simultaneously read and write to the same file from two processes, you need to open the file with the FileShare.ReadWrite option. The My.Computer.FileSystem methods don't do that.¹
However, I suspect that you don't really wan't to do that. I suspect that you want to write and, after you are finished writing, you want to read. In that case, just closing the file after using it will suffice. The easiest way to do that is to use the Using statement:
Using file = My.Computer.FileSystem.OpenTextFileWriter(...)
file.WriteLine(...)
file.WriteLine(...)
...
End Using
This ensures that the file will be closed properly as soon as the Using block is left (either by normal execution or by an exception). In fact, it is good practice to wrap use of every object whose class implements IDisposable (such as StreamWriter) in a Using statement.
¹ According to the reference source, OpenTextFileWriter creates a New IO.StreamWriter(file, append, encoding), which in turn creates a new FileStream(..., FileShare.Read, ...).

Process cannot access it is being used by another process

I got solution with three separated windows services. One services download files, second is taking the files and third one is loading to db. Sometimes during downlading files, second process is starting to play with it during its still downloading, or third process wants to load it but file is still parsing. I heard that Mutex could be resolution in my case but i am not sure how in this situation i could use it the other processes waits on files untill they are "free". Below i'll present you my code:
Downlading process part of code where file download is doing:
(in this case each file is downloading to specific location folder)
For Each item In RemoteFiles
Try
session.GetFiles(item, DownloadFolder, True, transferOptions).Check()
Catch ex As Exception
End Try
Next
Parsing win service process part of code which is parsing downloaded files:
Dim ColumnFound As Boolean = False
Using MyReader As New FileIO.TextFieldParser(fileToBeParsedPath)
Dim CurrentRecord As String() ' this array will hold each line of data
With MyReader
.TextFieldType = FileIO.FieldType.Delimited
.Delimiters = New String() {","}
.HasFieldsEnclosedInQuotes = True
End With
After that process each file are migrated to ParsedFolder. But data from it is saved in files with .dat extension. And those files are used by my Loader engine.
How can i do some "lock on file" for instance for files which are during download process to prevent parser to take them under parsing process and wait? Can i make some centralized place where file status will be saved, so parser after take existing files into the list and then when is going to open and parse them will check and wait untill its free?? Please about your advice/code.
EDITED:
•Ftp two files but only watch one. For example send the files important.txt and important.finish. Only watch for the finish file but process the txt.
•FTP one file but rename it when done. For example send important.wait and have the sender rename it to important.txt when finished.

Can't Delete INI File After Calling GetPrivateProfileString

I am having trouble deleting files after calling the GetPrivateProfileString command. I have the following code:
'Read the INI File
sb = New StringBuilder(500)
Select Case FileType
Case "Scanner File"
res = GetPrivateProfileString("ScannerSetings", "ScannerType", "", sb, sb.Capacity, Filename)
Case "Scale File"
res = GetPrivateProfileString("ScaleSetings", "ScaleType", "", sb, sb.Capacity, Filename)
End Select
'If the result is a value store it, otherwise move it to unprocessed
If res <> 0 Then InputArray.Add(sb.ToString)
File.Delete(Filename)
After reading the details from the INI file, as soon as I try to delete the file, I am getting the following error: The process cannot access the file 'R:\Drop\011_11_Scanner' because it is being used by another process.
I cannot even delete these files manually until I exit my application.
Any help would be appreciated.
Thanks
I cannot even delete these files manually until I exit my application.
This clearly shows that the file that Filename points to is locked. As long as it's locked, you won't be able to delete it.
Check your code for any file handles you have opened (eg for writing purposes) and did not close.
If you don't close a file after you've opened it, the file is not released and remains in locked state… which practically means it can not be deleted until (a) you close that file-handle, or (b) you close your program, since that's what's holding the file-handle after opening.
EDIT
The next thing that comes to mind is that VB.NET may need special user access rights to remove the INI on recent Windows versions. You can quickly cross-check that by simply executing your application with elevated user rights (eg via right-click menu; run as admin). I can't imagine that that's actually the problem — but it's worth a shot. Should it indeed be the problem, check (and modify) the permissions on the folder your application and/or INI resides in.

Cannot delete just created file

My application can create a directory, put a file in it from a ZIP file and then remove the ZIP file.
When I then try to delete that file, I get an Access Denied error even though nothing was done with it.
Here is the code:
File.WriteAllBytes(OpslagLocatieDocumenten + myTicketNummer.ToString + "\documenten.zip", op.Documenten)
Using zp As New ZipFile(OpslagLocatieDocumenten + myTicketNummer.ToString + "\documenten.zip")
zp.FlattenFoldersOnExtract = True
zp.ExtractAll(OpslagLocatieDocumenten + myTicketNummer.ToString, ExtractExistingFileAction.OverwriteSilently)
zp.Dispose()
End Using
Try
For Each itm As String In Directory.GetFiles(OpslagLocatieDocumenten + myTicketNummer.ToString)
Try
File.Delete(itm)
Catch ex As Exception
End Try
Next
Catch ex As Exception
End Try
It looks a bit messy right now, but that is for testing purposes.
In the for-next part, right after writing the file from the ZIP, I try to delete the files.
At the moment there are two files in the directory, one ZIP and one PDF document from the ZIP.
The first file in itm is the PDF, it errors with an ACCESS DENIED.
The second file in itm is the ZIP which gets deleted.
The PDF is 311 kb in size.
Via Windows explorer I can delete it without any problem, even with the application still running.
Why is my file being locked?
What can I do to by-pass or remove this lock?
rg,
Eric
Found the problem.
The file that was added to the ZIP had it's attribute set to READ ONLY.
So when the application writes the file, windows would, as it should, not allow the application to delete it.
Unfortunately, windows does allow to delete the file via windows explorer without a message that the file is read only.
Have you also tried the File.Kill(fileLocation) method?