VB.Net File.Exists() Returns True but Excel cannot Open - vb.net

I check for the existence of the file with File.Exists(filePath). Then I try to open the file from within Excel with Excel.Workbooks.OpenText(filePath). But Excel complains that the file's not there. What the heck?
The context is that I am shelling out to another application to process a given file and produce a .out file, which I then convert to an Excel workbook.
'' At this point, filePath is a .txt file.
Dim args As String = String.Format("""{0}""", filePath)
...
Dim exe As String = Config.ExtractEXE
Dim i As New ProcessStartInfo(exe)
i.Arguments = args
Dim p As Process = Process.Start(i)
p.WaitForExit()
...
'' filePath now becomes the .out file.
'' Then eventually, I get around to checking:
'If Not File.Exists(filePath) Then
' MsgBox("Please ensure...")
' Exit Sub
'End If
'' In response to an answer, I no longer check for the existence of the file, but
'' instead try to open the file.
Private Function fileIsReady(filePath As String) As Boolean
Try
Using fs As FileStream = File.OpenRead(filePath)
Return True
End Using
Catch
Return False
End Try
End Function
Do Until fileIsReady(filePath)
'' Wait.
Loop
ExcelFile.Convert(filePath...)
'' Wherein I make the call to:
Excel.Workbooks.OpenText(filePath...)
'' Which fails because filePath can't be found.
Is there a latency issue, such that .Net recognizes the existence of the file before it's accessible to other applications? I just don't understand why File.Exists() can tell me the file is there and then Excel can't find it.
As far as I know, the only application that might have the file open is the application I call to do the processing. But that application should be finished with the file by the time p.WaitForExit() finishes, right?
I've had to deploy the application with this as a known bug, which really sucks. There's an easy workaround for the user; but still--this bug should not be. Hope you can help.

Whether or not a file exists is not the only factor in whether you can open it. You also need to look at file system permissions and locking.
File.Exists can lie to you (it returns false if you pass a directory path or if any error occurs, even if the file does exist)
The file system is volatile, and things can change even in the brief period between an if (File.Exists(...)) line and trying to open the file in the next line.
In summary: you should hardly ever use file.exists(). Almost any time you are tempted to do so, just try to open the file and make sure you have a good exception handler instead.

Related

How to extract a zip file to directory and overwrite?

I made a little program that downloads a .zip file from my website and then later it installs in a specific directory. It works fine unless a file with the same name already exists, then I get an error. This is the code I have.
If Form1.CheckBox1.Checked = True Then
Label4.Text = "Downloading Test File!"
wc.DownloadFileAsync(New Uri("http://www.example.com/TestFile.zip"), Directory + "\TestFile.zip")
While wc.IsBusy = True
Application.DoEvents()
End While
ListBox1.Items.Add("Test File")
End If
'Install
If Form1.CheckBox1.Checked = True Then
ZipFile.ExtractToDirectory(Directory + "\TestFile.zip", Directory_Select.TextBox1.Text)
ListBox2.Items.Add("Test File")
End If
So for example, if the files inside "TestFile.zip" have the same name as Install location, it will give me following error:
The file 'filePath` already exists.
It doesn't finish extracting because a file with the same name already exists. Deleting the file beforehand is not a good solution because there will be multiple files with the same name.
How can I replace while extracting?
Also is there a way to pause the program till the file finishes extracting since some files are large and it takes some time before they are extracted.
Thanks in advance for helping me out, I am new and still learning. Appreciate your help.
Although the ExtractToDirectory method doesn't support overwriting files by default, the ExtractToFile method has an overload which takes a second boolean variable that allows you to overwrite the file being extracted. What you can do is to iterate over the files inside the archive and extract them one by one using ExtractToFile(filePath, True).
I have created an extension method which does just that and have been using it for a while. Hope you find it useful!
Add the following module to your project:
Module ZipArchiveExtensions
<System.Runtime.CompilerServices.Extension>
Public Sub ExtractToDirectory(archive As ZipArchive,
destinationDirPath As String, overwrite As Boolean)
If Not overwrite Then
' Use the original method.
archive.ExtractToDirectory(destinationDirPath)
Exit Sub
End If
For Each entry As ZipArchiveEntry In archive.Entries
Dim fullPath As String = Path.Combine(destinationDirPath, entry.FullName)
' If it's a directory, it doesn't have a "Name".
If String.IsNullOrEmpty(entry.Name) Then
Directory.CreateDirectory(Path.GetDirectoryName(fullPath))
Else
entry.ExtractToFile(fullPath, True)
End If
Next entry
End Sub
End Module
Usage:
Using archive = ZipFile.OpenRead(archiveFilePath)
archive.ExtractToDirectory(destPath, True)
End Using
Side note: Don't concatenate strings to form a path out of its parts; use Path.Combine() instead.

Visual Basic don't see application.evtx

I have a problem with "Application.evtx" file. Everytime I run my script I get the message box with "File not found" information and I don't know why. I ran Visual Studio as administrator. Help me with this one, please.
Imports System.IO
Module Module1
Sub Main()
Dim pathReadFile As String = "c:\Windows\System32\winevt\Logs\Application.evtx"
'Dim pathReadFile As String = "%windir%\Sysnative\winevt\Logs\Application.evtx"
'Dim pathReadFile As String = "D:\Dokumenty\MyTest.txt"
Try
If File.Exists(pathReadFile) Then
MsgBox("File found.")
Else
MsgBox("File not found.")
End If
Catch ex As Exception
End Try
End Sub
End Module
Don't use File.Exists(). Ever.
There are many reasons for this, but the one that impacts you right now is that it lies to you and tells you the file does not exist, even if the file actually does exist and the real problem is that you don't have permissions to use it. From the docs:
Return Value
Type: System.Boolean
true if the caller has the required permissions and path contains the name of an existing file; otherwise, false
Remember that normal users have extremely limited file system permissions outside of their own home folders, and even Administrator users need to explicitly run a process as elevated or UAC will just give them normal user permissions.
You have to handle the exception anyway if reading the file fails. Put your development effort into the exception handler.
While I'm here, you may also want to build your path like this:
Dim pathReadFile As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "winevt\Logs\Application.evtx")

VBA.FileSystem Dir

In VB6 code i m using VBA.FileSystem.Dir to get file name from a directory path. But it is returning empty string. Please find the below code
Call getFile.ShowOpen //getFile is CommonDialog Control of VB6
txtFile.Text = getFile.FileTitle //Correct file name is returned
If Dir(getFile.filename) == "" Then
// Conditions come true..But ideally it should not!!!
But the file resides in some network location. Can there be any permission issue? If yes, How do i see that file in getFile.ShowOpen dialog and Dir() returns empty string?
Any help on what is wrong in the above code
Consider these points:
afaik, the double equal ( == ) is not supported in vb6
Dir = (whatever) can return ""
if whatever is a directory or hidden file
You could trap just the name by using
If Dir(whatever, vbDirectory Or vbHidden Or vbArchive Or vbNormal)
But you would still have to test each to see what it was.
btw, it's better to have a variable to receive Dir and inspect that, rather than inspecting Dir itself.
dim sTgt$
sTgt = Dir(whatever)
Also, btw, an alternative to chking each type is to to inspect FileLen.
Curiously, FileLen was not affected by the Hidden/Sys attribs, although it will err out if the file does not exist.
So, (and this is really old hacking stuff but handy code).
If you declare a variable for FileLen
Dim lfLen&
'and have some error coding
On Error resume next
'and then just inspect the target
lfLen = FileLen(stgt)
if lflen > 0 then
... do things
(or if hacking)
... binary open
Because, If the file no exist,
a directory will return 0,
but if file = archive, hidden, sys it will return bytes.
hth
Gary

Access to path is denied when trying to import from the client's desktop with SSIS

I'm creating a html page that will import an excel file in to a tracking system. On a button click event excel file is located / ssis package is fired / data imported then closed out. Thats the idea work flow. Problem is the excel file access is being denied before the package even executes
Here is the exact error :
I've tried :
excel file properties have been shared to everyone
identity impersonate set to true
hard coding the path
here is the VB code
Protected Sub bntExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim app As Application = New Application()
Dim package As Package = Nothing
'Dim fileName As String = "C:\Users\Desktop\T. Bryant III\PTSID_Update_Template"'
Try
Dim fileName As String = Server.MapPath(System.IO.Path.GetFileName(FileUpload1.PostedFile.FileName.ToString()))
FileUpload1.PostedFile.SaveAs(fileName)
package = app.LoadPackage("#C:\Users\Desktop\T.Bryant III\KitImport", Nothing)
'excel connection from package'
package.Connections("SourceConnectionExcel").ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0data source =" + fileName + "Extended Properties = Excel 8.0"
'Execute the pakage'
Dim results As Microsoft.SqlServer.Dts.Runtime.DTSExecResult = package.Execute()
Catch ex As Exception
Throw ex
Finally
package.Dispose()
package = Nothing
End Try
End Sub
Thanks in advance or if there is an easier way to do this please let me know. The package when executing it in ssis works fine with its own connection manager etc.
A few things to try. If they don't work for you as permanent solutions, they should at least confirm that your code is working and you are dealing with a persmissions issue (which appears to be the case).
Move your file to the public folder (C:\Users\Public).
Run your application (or web browser) as an administrator (if applicable to your version of Windows).
If you are using a web browser, try using a different one.
If nothing else works, try pasting your code into a Windows Form Application.
If you still get the same error after trying all of this, it's time to take another look at your code. Remove the Try/Catch block to determine precisely which line is throwing the error. If you've tried hard coding, I'm guessing it's the SaveAs method. I'm not sure what class FileUpload1 is, but some SaveAs methods won't overwrite existing files unless you explicitly tell them to. Check the appropriate documentation and see if you don't need to pass a True value somewhere along with filename.
Update us with the results. At the very least, this should narrow down your problem and allow for a better diagnosis of it.

Program not able to write to a newly made text file

After some great arguments made by other users in this question: How to write to a text file inside of the application, I decided to not use a resource file, instead create a file in a folder & then read/write from there.
Although, for some reason, I can't seem to write to the file in question, it keeps throwing an exception telling me the file is already in use by another process.
Here's the code which I use for writing to this file.
If System.IO.File.Exists(credentials) Then
Dim objWriter As New System.IO.StreamWriter(credentials, False)
objWriter.WriteLine(remember)
objWriter.Close()
Else
System.IO.Directory.CreateDirectory(Mid(My.Application.Info.DirectoryPath, 1, 1) & ":\ProgramData\DayZAdminPanel")
System.IO.File.Create(credentials)
Dim objWriter As New System.IO.StreamWriter(credentials, False)
objWriter.WriteLine(remember)
objWriter.Close()
End If
Any ideas on how I can write to the text file in question?
There's a good chance that a previous iteration of your application failed to properly close access to the file in the StreamWriter. Since your constructor is set to overwrite (and not append) to the file, this could be the source.
Try setting up your application with a "Using" statement to properly open/close the file:
If System.IO.File.Exists(credentials) Then
Using objWriter As StreamWriter = New StreamWriter(credentials, False)
objWriter.WriteLine(remember)
objWriter.Close()
End Using
Else
System.IO.Directory.CreateDirectory(Mid(My.Application.Info.DirectoryPath, 1, 1) & ":\ProgramData\DayZAdminPanel")
System.IO.File.Create(credentials)
Using objWriter As StreamWriter = New StreamWriter(credentials, False)
objWriter.WriteLine(remember)
objWriter.Close()
End Using
End If
It does look rather redundant to have a Using block and a close statement, but this ensures access to your file even if an exception occurs.
You are trying to create a directory in the common application data directory. This directory should be found using the Environment class methods and enums because is different between operating systems. However you use the value credentials for the filename. I suppose that you want to store your datafile in the common application directory and not in a place where there is no permission to write data files (Like C:\program files (x86)).
Then, to avoid problems with file stream not correctly closed try to use the Using statement that assures a correct closure and disposal of your file resource (No need to call close inside a Using).
Also, notice that StreamWriter is perfectly capable to create the file if it doesn't exists or if you wish to overwrite the previous contents (passing false for the Append flag).
So your code could be reduced to these lines.
' Get the common application data directory (could be different from Win7 and XP)
Dim workDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
' Combine with your own working data directory
workDir = Path.Combine(workdir, "DayZAdminPanel")
' Create if not exists
If Not Directory.Exists(workDir) Then
Directory.CreateDirectory(workDir)
End If
' Create/Overwrite your data file in a subfolder of the common application data folder
Dim saveFile = Path.Combine(workDir, Path.GetFileName(credentials))
Using objWriter = New System.IO.StreamWriter(saveFile, False)
objWriter.WriteLine(remember)
End Using
File.Create returns an opened FileStream that you should be passing into the StreamWriter constructor on the subsequent, rather than passing the filename again, or you can just omit the File.Create call altogether.
You might want to look into a Using block for the StreamWriter so it gets predictably closed.