how do I add a path to a code where "HERE_HAS_TO_BE_A_PATH" is. When I do, Im getting an error message. The goal is to be able to specific the path where is the final text file saved.
Thanks!
Here is a code:
Dim newFile As IO.StreamWriter = IO.File.CreateText("HERE_HAS_TO_BE_A_PATH")
Dim fix As String
fix = My.Computer.FileSystem.ReadAllText("C:\test.txt")
fix = Replace(fix, ",", ".")
My.Computer.FileSystem.WriteAllText("C:\test.txt", fix, False)
Dim query = From data In IO.File.ReadAllLines("C:\test.txt")
Let name As String = data.Split(" ")(0)
Let x As Decimal = data.Split(" ")(1)
Let y As Decimal = data.Split(" ")(2)
Let z As Decimal = data.Split(" ")(3)
Select name & " " & x & "," & y & "," & z
For i As Integer = 0 To query.Count - 1
newFile.WriteLine(query(i))
Next
newFile.Close()
1) Use a literal string:
The easiest way is replacing "HERE_HAS_TO_BE_A_PATH" with the literal path to desired output target, so overwriting it with "C:\output.txt":
Dim newFile As IO.StreamWriter = IO.File.CreateText("C:\output.txt")
2) Check permissions and read/write file references are correct:
There's a few reasons why you might be having difficulties, if you're trying to read and write into the root C:\ directory you might be having permissions issues.
Also, go line by line to make sure that the input and output files are correct every time you are using one or the other.
3) Make sure the implicit path is correct for non-fully qualified paths:
Next, when you test run the program, it's not actually in the same folder as the project folder, in case you're using a relative path, it's in a subfolder "\bin\debug", so for a project named [ProjectName], it compiles into this folder by default:
C:\path\to\[ProjectName]\bin\Debug\Program.exe
In other words, if you are trying to type in a path name as a string to save the file to and you don't specify the full path name starting from the C:\ drive, like "output.txt" instead of "C:\output.txt", it's saving it here:
C:\path\to\[ProjectName]\bin\Debug\output.txt
To find out exactly what paths it's defaulting to, in .Net Framework you can check against these:
Application.ExecutablePath
Application.StartupPath
4) Get user input via SaveFileDialogue
In addition to a literal string ("C:\output.txt") if you want the user to provide input, since it looks like you're using .Net Framework (as opposed to .Net Core, etc.), the easiest way to set a file name to use in your program is using the built-in SaveFileDialogue object in System.Windows.Forms (like you see whenever you try to save a file with most programs), you can do so really quickly like so:
Dim SFD As New SaveFileDialog
SFD.Filter = "Text Files|*.txt"
SFD.ShowDialog()
' For reuse, storing file path to string
Dim myFilePath As String = SFD.FileName
Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' path var
' Do the rest of your code here
newFile.Close()
5) Get user input via console
In case you ever want to get a path in .Net Core, i.e. with a console, the Main process by default accepts a String array called args(), here's a different version that lets the user add a path as the first parameter when running the program, or if one is not provided it asks the user for input:
Console.WriteLine("Hello World!")
Dim myFilePath = ""
If args.Length > 0 Then
myFilePath = args(0)
End If
If myFilePath = "" Then
Console.WriteLine("No file name provided, please input file name:")
While (myFilePath = "")
Console.Write("File and Path: ")
myFilePath = Console.ReadLine()
End While
End If
Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' path var
' Do the rest of your code here
newFile.Close()
6) Best practices: Close & Dispose vs. Using Blocks
In order to keep the code as similar to yours as possible, I tried to change only the pieces that needed changing. Vikyath Rao and Mary respectively pointed out a simplified way to declare it as well as a common best practice.
For more information, check out these helpful explanations:
Can any one explain why StreamWriter is an Unmanaged Resource. and
Should I call Close() or Dispose() for stream objects?
In summary, although streams are managed and should garbage collect automatically, due to working with the file system unmanaged resources get involved, which is the primary reason why it's a good idea to manually dispose of the object. Your ".close()" does this. Overrides for both the StreamReader and StreamWriter classes call the ".dispose()" method, however it is still common practice to use a Using .. End Using block to avoid "running with scissors" as Enigmativity puts it in his post, in other words it makes sure that you don't go off somewhere else in the program and forget to dispose of the open filestream.
Within your program, you could simply replace the "Dim newFile As IO.StreamWriter = IO.File.CreateText("C:\output.txt")" and "newFile.close()" lines with the opening and closing statements for the Using block while using the simplified syntax, like so:
'Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' old
Using newFile As New IO.StreamWriter(myFilePath) ' new
Dim fix As String = "Text from somewhere!"
newFile.WriteLine(fix)
' other similar operations here
End Using ' new -- ensures disposal
'newFile.Close() ' old
You can write that in this way. The stream writer automatically creates the file.
Dim newFile As New StreamWriter(HERE_HAS_TO_BE_A_PATH)
PS: I cannot mention all these in the comment section as I have reputations less than 50, so I wrote my answer. Please feel free to tell me if its wrong
regards,
vikyath
Related
I am using a legacy application where all the source code is in vb.net. I am checking if the file exists and if the condition is true replace all the " in the contents of the file. For instance "text" to be replaced as text. I am using the below code.
vb.net
Dim FileFullPath As String
FileFullPath = "\\Fileshare\text\sample.txt"
If File.Exists(FileFullPath) Then
Dim stripquote As String = FileFullPath
stripquote = stripquote.Replace("""", "").Trim()
Else
'
End If
I get no errors and at the same time the " is not being replaced in the content of the file.
Data:
ID, Date, Phone, Comments
1,05/13/2021,"123-000-1234","text1"
2,05/13/2021,"123-000-2345","text2"
3,05/13/2021,"123-000-3456","text2"
Output:
1,05/13/2021,123-000-1234,text1
2,05/13/2021,123-000-2345,text2
3,05/13/2021,123-000-3456,text2
You can read each line of the file, remove the double-quotes, write that to a temporary file, then when all the lines are done delete the original and move/rename the temporary file as the filename:
Imports System.IO
'...
Sub RemoveDoubleQuotes(filename As String)
Dim tmpFilename = Path.GetTempFileName()
Using sr As New StreamReader(filename)
Using sw As New StreamWriter(tmpFilename)
While Not sr.EndOfStream
sw.WriteLine(sr.ReadLine().Replace("""", ""))
End While
End Using
End Using
File.Delete(filename)
File.Move(tmpFilename, filename)
End Sub
Add error handling as desired.
The best way to go about this depends on the potential size of the file. If the file is relatively small then there's no point processing it line by line and certainly not using a TextFieldParser. Just read the data in, process it and write it out:
File.WriteAllText(FileFullPath,
File.ReadAllText(FileFullPath).
Replace(ControlChars.Quote, String.Empty))
Only if the file is potentially large and reading it all in one go would require too much memory should you consider processing it line by line. In that case, I'd go this way:
'Let the system create a temp file.
Dim tempFilePath = Path.GetTempFileName()
'Open the temp file for writing text.
Using tempFile As New StreamWriter(tempFilePath)
'Open the source file and read it line by line.
For Each line In File.ReadLines(FileFullPath)
'Remove double-quotes from the current line and write the result to the temp file.
tempFile.WriteLine(line.Replace(ControlChars.Quote, String.Empty))
Next
End Using
'Overwrite the source file with the temp file.
File.Move(tempFilePath, FileFullPath, True)
Note the use of File.ReadLines rather than File.ReadAllLines. The former will only read one line at a time where the latter reads every line before you can process any of them.
EDIT:
Note that this:
File.Move(tempFilePath, FileFullPath, True)
only works in .NET Core 3.0 and later, including .NET 5.0. If you're targeting .NET Framework then you have three other options:
Delete the original file (File.Delete) and then move the temp file (File.Move).
Copy the temp file (File.Copy) and then delete the temp file (File.Delete).
Call My.Computer.FileSystem.MoveFile to move the temp file and overwrite the original file in one go.
TextFieldParser is probably the way to go.
Your code with a few changes.
Static doubleQ As String = New String(ControlChars.Quote, 2)
Dim FileFullPath As String
FileFullPath = "\\Fileshare\text\sample.txt"
If IO.File.Exists(FileFullPath) Then
Dim stripquote As String = IO.File.ReadAllText(FileFullPath)
stripquote = stripquote.Replace(doubleQ, "").Trim()
Else
'
End If
Note the static declaration. I adopted this approach because it confused the heck out of me.
I am trying to extract an application resource from My.Resources.FILE
I have discovered how to do this with DLL & EXE files, but I still need help with the code for extracting PNG & ICO files.
Other file types also. (If possible)
Here is my current code that works with DLL & EXE files.
Dim File01 As System.IO.FileStream = New System.IO.FileStream("C:\Users\" + Environment.UserName + "\Desktop\" + "SAMPLE.EXE", IO.FileMode.Create)
File01.Write(My.Resources.SAMPLE, 0, My.Resources.SAMPLE.Length)
File01.Close()
First things first, the code you have is bad. When using My.Resources, every time you use a property, you extract a new copy of the data. That means that your second line is getting the data to write twice, with the second time being only to get its length. At the very least, you should be getting the data only once and assigning it to a variable, then using that variable twice. You should also be using a Using statement to create and destroy the FileStream. Even better though, just call File.WriteAllBytes, which means that you don't have to create your own FileStream or know the length of the data to write. You should also not be constructing the file path that way.
Dim filePath = Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "SAMPLE.EXE")
File.WriteAllBytes(filePath, My.Resources.SAMPLE)
As for your question, the important thing to understand here is that it really has nothing to do with resources. The question is really how to save data of any particular type and that is something that you can look up for yourself. When you get the value of a property from My.Resources, the type of the data you get will depend on the type of the file you embedded in first place. In the case of a binary file, e.g. DLL or EXE, you will get back a Byte array and so you save that data to a file in the same way as you would any other Byte array. In the case of an image file, e.g. PNG, you will get back an Image object, so you save that like you would any other Image object, e.g.
Dim filePath = Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "PICTURE.PNG")
Using picture = My.Resources.PICTURE
picture.Save(filePath, picture.RawFormat)
End Using
For an ICO file you will get back an Icon object. I'll leave it to you to research how to save an Icon object to a file.
EDIT:
It's important to identify what the actual problem is that you're trying to solve. You can obviously get an object from My.Resources so that is not the problem. You need to determine what type that object is and determine how to save an object of that type. How to do that will be the same no matter where that object comes from, so the resources part is irrelevant. Think about what it is that you have to do and write a method to do it, then call that method.
In your original case, you could start like this:
Dim data = My.Resources.SAMPLE
Once you have written that - even as you write it - Intellisense will tell you that the data is a Byte array. Your actual problem is now how to save a Byte array to a file, so write a method that does that:
Private Sub SaveToFile(data As Byte(), filePath As String)
'...
End Sub
You can now which you want to do first: write code to call that method as appropriate for your current scenario or write the implementation of the method. There are various specific ways to save binary data, i.e. a Byte array, to a file but, as I said, the simplest is File.WriteAllBytes:
Private Sub SaveToFile(data As Byte(), filePath As String)
File.WriteAllBytes(filePath, data)
End Sub
As for calling the method, you need to data, which you already have, and the file path:
Dim data = My.Resources.SAMPLE
Dim folderPath = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim fileName = "SAMPLE.EXE"
Dim filePath = Path.Combine(folderPath, fileName)
SaveToFile(data, filePath)
Simple enough. You need to follow the same steps for any other resource. If you embedded a PNG file then you would find that the data is an Image object or, more specifically, a Bitmap. Your task is then to learn how to save such an object to a file. It shouldn't take you long to find out that the Image class has its own Save method, so you would use that in your method:
Private Sub SaveToFile(data As Image, filePath As String)
data.Save(filePath, data.RawFormat)
End Sub
The code to call the method is basically as before, with the exception that an image object needs to be disposed when you're done with it:
Dim data = My.Resources.PICTURE
Dim folderPath = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim fileName = "SAMPLE.EXE"
Dim filePath = Path.Combine(folderPath, fileName)
SaveToFile(data, filePath)
data.Dispose()
The proper way to create and dispose an object in a narrow scope like this is with a Using block:
Dim folderPath = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim fileName = "SAMPLE.EXE"
Dim filePath = Path.Combine(folderPath, fileName)
Using data = My.Resources.PICTURE
SaveToFile(data, filePath)
End Using
Now it is up to you to carry out the same steps for an ICO file. If you are a hands on learner then get your hands on.
This is the code I'm Using:
Dim file As String
Dim prefetchPath As String
Dim FileName As String = My.Application.Info.AssemblyName
prefetchPath = Environment.GetEnvironmentVariable("windir", EnvironmentVariableTarget.Machine) & "\Prefetch"
For Each file In IO.Directory.GetFiles(prefetchPath)
If file.Contains(FileName) Then
IO.File.Delete(file)
End If
Next
i don't know why it does not work if i use FileName. But it work if i use this code
If file.Contains("Example.exe") Then
IO.File.Delete(file)
End If
I want to make sure that if someone changes the name of the application the code works the same way(I already running the file as Administrator)
Help me Thanks.
My guess is that AssemblyName only returns the name without the extension, try including the .exe. Also, it is worth noting that you can use the IO.DirectoryInfo class and pass the file name in the GetFiles method to cut out your For/Each loop.
Here is a quick example:
Dim prefetchPath As String = IO.Path.Combine(Environment.GetEnvironmentVariable("windir", EnvironmentVariableTarget.Machine), "Prefetch")
Dim FileName As String = My.Application.Info.AssemblyName & ".exe"
If New IO.DirectoryInfo(prefetchPath).GetFiles(FileName).Count > 0 Then
IO.File.Delete(IO.Path.Combine(prefetchPath, FileName))
End If
I have a database split in FrontEnd and BackEnd.
I have it running:
i) in my office
ii) updating/testing in my personal computer.
My BackEnd file is running in different Folder location according to computer running.
I want to place a code and check if file exist.
Code:
Sub FileExists()
Dim strPath As String '<== Office.
Dim strApplicationFolder As String
Dim strPathAdmin As String '<== Admin.
strPath = "\\iMac\Temp\"
strApplicationFolder = Application.CurrentProject.Path
strPathAdmin = strApplicationFolder & "\Temp\"
If Dir(strApplicationFolder & "SerialKey.txt") = "" Then
'===> Admin User.
If Dir(strPathAdmin & "*.*") = "" Then
'===> Empty Folder.
Else
'===> Files on folder.
End If
Else
'===> Office User.
If Dir(strPath & "*.*") = "" Then
'===> Empty Folder.
Else
'===> Files on folder.
End If
End If
End Sub()
I have this until now.
Any help.
Thank you...
Create a small function to check if a file exists and call it when needed.
Public Function FileExists(ByVal path_ As String) As Boolean
FileExists = (Len(Dir(path_)) > 0)
End Function
Since the backend database paths dont change, why dont you declare two constants and simply check their value?
Sub Exist()
Const workFolder As String = "C:\Work Folder\backend.accdb"
Const personalFolder As String = "D:\Personal Folder\backend.accdb"
If FileExists(workFolder) Then
'Work folder exists
End If
'....
If FileExists(personalFolder) Then
'Personal folder exists
End If
End Sub
This is a very belated reply, but don't reinvent the wheel. VBA can access the FileSystemObject, which includes a powerful set of methods that fetch file and folder information without requiring you to write your own functions, and the resulting code is much easier to read.
Second, borrowing on the previous answer, you know the folders you want the code to look at, and they don't change much, but because they could, I would also move your parameters into the declaration so they can be customized if needed or default to existing values.
Finally, FileExists is a verb, which should scream Function rather than Sub, so I'm guessing you want to return something and use it elsewhere in higher level code. It so happens that FileExists is already the name of a method in FileSystemObject, so I'm going to rename your function to LocatePath. You could return the valid path of the file you're looking for and decide by convention to quietly return an empty string "" if the target isn't found, and handle that in the calling procedure.
fs.BuildPath(strRootPath, strFileOrSubDir) appends strFileOrSubDir to strRootPath to construct a properly
formatted, full pathname and you don't need to worry about
whether you have backslashes (or too many) between the two.
It can be used to append files, or subdirectories, or
files in subdirectories.
fs.FileExists(strFullPath) is simple, returns True if strFullPath exists,
and False otherwise.
fs.GetFolder(strFolderName) returns a Folder object that has a
.Files property, which is a Collection object. Collection
objects in turn have a .Count property, which in this example
indicates how many files are in strFolderName. The Collection
object could also be used to iterate over all the files in the
folder individually.
What follows is your code refactored to incorporate all the changes I recommend according to what I think you're trying to achieve. It's not as symmetric as I'd like, but mirrors your code, and it's simple, easy to read, and finished in the sense that it does something.
Function LocatePath(Optional strWorkPath as String = "\\iMac",
Optional strHomePath as String = CurrentProject.Path,
Optional strFile as String = "SerialKey.txt"
Optional strSubDir as String = "Temp") as String
Dim fs as Object
Set fs = CreateObject("Scripting.FileSystemObject")
If fs.FileExists(fs.BuildPath(strHomePath, strFile)) Then
If fs.GetFolder(fs.BuildPath(strHomePath, strSubDir).Files.Count > 0 Then '===> Admin User.
LocatePath = fs.BuildPath(strHomePath, strFile)
ElseIf fs.GetFolder(fs.BuildPath(strWorkPath, strSubDir).Files.Count > 0 Then '===> Office User
LocatePath = fs.BuildPath(strWorkPath, strFile)
End If
Else 'Target conditions not found
LocatePath = ""
End If
Set fs = Nothing
End Function()
Ideally, I probably wouldn't specify strHomePath as String = CurrentProject.Path because strWorkPath as String = CurrentProject.Path is probably also true when you're at work, and you would want to do a better job of differentiating between the two environments. This is also what causes the little problem with symmetry that I mentioned.
I am trying to writeline into a text file this works accept it appears to overwrite the last line each time. I would like it to write to the next line instead of overwriting. Here is the code I'm using
Dim FileNumber As Integer = FreeFile()
FileOpen(FileNumber, "c:\Converted.txt", OpenMode.Output)
PrintLine(FileNumber, convertedDir)
FileClose(FileNumber)
You are using an old (VB6/VBA) code, better use the .NET StreamWriter:
Dim append As Boolean = True
Using writer As System.IO.StreamWriter = New System.IO.StreamWriter("c:\Converted.txt", append)
writer.WriteLine(convertedDir)
End Using
append indicates whether the given file should be appended. Nonetheless, as suggested by Boris B., you can set this variable always to True because StreamWriter is capable to deal with both situations (existing file or not) automatically.
In any case, I am including below the "theoretically right" way to deal with StreamWriter (by changing the append property depending upon the fact that the given file is present or not):
Dim append As Boolean = False
Dim fileName As String = "c:\Converted.txt"
If (System.IO.File.Exists(fileName)) Then
append = True
End If
Using writer As System.IO.StreamWriter = New System.IO.StreamWriter(fileName, append)
writer.WriteLine(convertedDir) 'Writes to a new line
End Using
For a quick solution based on existing code change the line
FileOpen(FileNumber, "c:\Converted.txt", OpenMode.Output)
to
FileOpen(FileNumber, "c:\Converted.txt", OpenMode.Append)
However, you should really update your method of writing files, since FileOpen and similar are there just for compatibility with older VB & VBA programs (and programmers :). For a more modern solution check out varocarbas' answer.