File.Exists Is Not Adding File Number to Existing File in Directory Before Saving - vb.net

I'm trying to check if the file exists in the directory in which the application was saved and if so, to add a number at the end -1, -2. -3 - based on whether a file with the same name already exists. My code is below:
Dim FileName, FilePath As String
Dim FileNumber As Integer
FileName = ProjectName
FilePath = Path.Combine(CurrentDirectory, FileName)
If File.Exists(FilePath) = True Then
Do While File.Exists(FilePath)
FileNumber = FileNumber + 1
FileName = FileName & "-" & FileNumber
FilePath = Path.Combine(CurrentDirectory, FileName)
Loop
End If
NewWorkbook.SaveAs(FilePath)
When I run this code and the file is saving the first time, it works as intended but if I try saving the file with the same name a second time, there is no iterated FileNumber added to it, so the file name stays the same and it cannot save without replacing the original file.
Why is the File.Exists not recognizing that this file already exists and how can I fix this?

There is a logical problem in your code. You continue to modify the same variable and building continuosly new names.
For example. Suppose to have initially a file with the name "Project.vb". At the first iteration inside the loop you check for a file named "Project.vb1", if your loop continues at the second iteration you check for a file named "Project.vb12" and so on.
A more correct way could be
Dim FileName, FileWithoutExtension, FileExtension, FilePath As String
Dim FileNumber As Integer = 1
Dim currentDirectory As String = "E:\temp" ' as an example
FileName = "test.txt" ' as an example
FileExtension = Path.GetExtension(FileName)
FileWithoutExtension = Path.GetFileNameWithoutExtension(FileName)
FilePath = Path.Combine(CurrentDirectory, FileName)
' No need of additional if to test file existance.
Do While File.Exists(FilePath)
FileNumber = FileNumber + 1
' Rebuild the Filename part wtih all the info
FileName = FileWithoutExtension & "-" & FileNumber.ToString("D3") + FileExtension
FilePath = Path.Combine(CurrentDirectory, FileName)
Loop
NewWorkbook.SaveAs(FilePath)

Related

FileExist returns false

I have a folder with 700+ .jpgs. I also have a Textbox with one filename per line.
I want to check which file does not exist in the folder, but should be there.
This is my code:
Dim Counter As Integer = 0
For Each Line As String In tbFileNames.Lines
Counter = Counter + 1
If (IO.File.Exists(tbFolder.Text & "\" & tbFileNames.Lines(Counter - 1).ToString & ".jpg")) = False Then
tbNotExistingFiles.Text = tbNotExistingFiles.Text & vbNewLine & (tbFileNames.Lines(Counter - 1).ToString)
Else
End If
Next
Problem: I get more than 300 "missing" files, but there should be only 7. When I search for the output filenames, they are in the folder, so the FileExists functions returns false, but it shouldn't.
Where is the problem? Is it the amount of files?
According to this line:
If (IO.File.Exists(tbFolder.Text & "\" & tbFileNames.Lines(Counter - 1).ToString & ".jpg")) = False
Which can be interpreted as:
The tbFolder TextBox contains the directory's path where the images are located.
The tbFileNames TextBox contains the main and complete file names. One file name per line.
Appending the extension & ".jpg" means that the file names in the tbFileNames TextBox are without extensions. And,
You need to get a list of the missing files in that directory and show the result in the tbNotExistingFiles TextBox.
If my interpretation is correct, then you can achieve that using the extension methods like:
Imports System.IO
'...
Dim missingFiles = tbFileNames.Lines.
Select(Function(x) $"{x.ToLower}.jpg").
Except(Directory.GetFiles(tbFolder.Text).
Select(Function(x) Path.GetFileName(x.ToLower)))
tbNotExistingFiles.Text = String.Join(ControlChars.NewLine, missingFiles)
Or by a LINQ query:
Dim missingFiles = From x In tbFileNames.Lines
Where (
Aggregate y In Directory.EnumerateFiles(tbFolder.Text)
Where Path.GetFileName(y).ToLower.Equals($"{x.ToLower}.jpg")
Into Count()
) = 0
Select x
'Alternative to tbNotExistingFiles.Text = ...
tbNotExistingFiles.Lines = missingFiles.ToArray
Note that, there's no need nor use for the File.Exists(..) function in the preceding snippets. Just in case you prefer your approach using For..Loop and File.Exists(..) function, then you can do:
Dim missingFiles As New List(Of String)
For Each line In tbFileNames.Lines
If Not File.Exists(Path.Combine(tbFolder.Text, $"{line}.jpg")) Then
missingFiles.Add(line)
End If
Next
tbNotExistingFiles.Lines = missingFiles.ToArray

Excel VBA user defined function to find images in folder (match excel names to folder names of images)

Currently i am using a function to match image names from excel sheet to image folder, but i want one more thing... that if i save image and forget to add its name in excel then it should show me that i forget to add name.
for example if i save 3 images in image folder
16095_1.jpg,16095_2.jpg,16095_3.jpg
and i add image names in excel sheet as
16095_1.jpg,16095_2.jpg
then it should warn me that i forget one image name in excel cell.
my image name format is - 16095_1.jpg,16095_2.jpg
function i am using is...
Function findimage(Path As String, ImageList As String)
Dim results
Dim x As Long
Dim dc 'double comma
results = Split(ImageList, ",")
If Not Right(Path, 1) = "\" Then Path = Path & "\"
For x = 0 To UBound(results)
results(x) = Len(Dir(Path & results(x))) > 0
Next
dc = InStr(ImageList, ",,")
If dc = 0 Then
findimage = Join(results, ",")
Else
findimage = ("Double_comma")
End If
End Function
This function takes a folder path and a variable number of patterns (See MSDN - Parameter Arrays (Visual Basic)). Using the MSDN - Dir Function to iterates over the file names in the folder path and compares them against the patterns with the MSDN - Like Operator (Visual Basic) to count the number of files that match the patterns.
Usage:
getFileCount("C:\Users\Owner\Pictures",".gif",".png")
getFileCount("C:\Users\Owner\Pictures","*.gif"
getFileCount("C:\Users\Owner\Pictures","apple_.gif","banana_.gif", "orange_##.*")
getFileCount("C:\Users\Owner\Pictures","#####_#.gif")
Function getFileCount(DirPath As String, ParamArray Patterns() As Variant) As Integer
Dim MyFile As String
Dim count As Integer, x As Long
If Not Right(DirPath, 1) = "\" Then DirPath = DirPath & "\"
MyFile = Dir(DirPath, vbDirectory)
Do While MyFile <> ""
For x = 0 To UBound(Patterns)
If MyFile Like Patterns(x) Then
count = count + 1
Exit For
End If
Next
MyFile = Dir()
Loop
getFileCount = count
End Function

Renaming multiple files by name

I'm writing a little program that is supposed to rename multiple files in a chosen directory by the filenames.
this is what I use now:
Dim sourcePath As String = dir
Dim searchPattern As String = "*." & ComboBox3.Text
Dim i As Integer = 1
For Each fileName As String In Directory.GetFiles(sourcePath, searchPattern, SearchOption.AllDirectories)
File.Move(Path.Combine(sourcePath, fileName), Path.Combine(sourcePath, type & i & "." & ComboBox3.Text))
i += 1
Next
But i want it to be more like:
For Each fi As FileInfo In Directory.GetFiles(searchPattern).OrderBy(Function(s) s.FullName)
File.Move(Path.Combine(sourcePath, fileName), Path.Combine(sourcePath, type & i & "." & ComboBox3.Text))
i += 1
Next
This is how far I've gotten, but it's not working as i hoped.
Also, I was wondering if it is possible to exclude file-types with the GetFiles, i don't want it to rename text-files.
Thanks :)
Edit:
The first code works almost perfect, it takes the dir from a 'FolderBrowserDialog' and renames all the files within the path-folder. The problem is that it sometimes get the order wrong: lets say i got these 3 files:
01Movie.avi, 07Movie.avi and 11Movie.avi
I want them to be renamed in the order they are in the folder by name:
01Movie.avi should be Movie1.avi, 07Movie.avi -> Movie2.avi and 11Movie.avi -> Movie3.avi
Try not to modify a collection you are still looping through. Created a detatched array to work with. Then sort your new array to get them in the order you described.
Keep in mind that you have SearchOption.AllDirectories, this is going to return subs, so your filename array may not be what you were thinking... Either change the logic of the sort or handle subs separately.
'detached array of file names
Dim fileNames() As String = Directory.GetFiles(sourcePath, searchPattern)
'sort the names System.Array.Sort(Of String)(fileNames)
Dim newFileName As String
For Each fileName As String In fileNames
'manipulate you filename here
'Path.GetFileNameWithoutExtension(fileName) might help
'Path.GetExtension(fileName) might help
newFileName = "newFileNameWithoutExtension" & i.ToString
File.Move(Path.Combine(Path.GetDirectoryName(fileName), fileName), Path.Combine(Path.GetDirectoryName(fileName), newFileName))
i += 1
Next

Nested Loop Not Working vb.net

I am trying to read file names from source directory and then read a separate file to rename and move files to target directory. Below code reads the file names but the problem is it only reading the contents of app.ini file only once i.e. for first file name. Code is not looping app.ini as soon as for loops switches to second file name.
Dim di As New IO.DirectoryInfo("D:\Transcend")
Dim diar1 As IO.FileInfo() = di.GetFiles()
Dim dra As IO.FileInfo
If (di.GetFiles.Count > 0) Then
Dim a As Integer = 1
Dim b As Integer = 1
For Each dra In diar1
ComboBox1.Items.Add(dra.FullName.ToString)
Using reader2 As New IO.StreamReader("D:\Transcend\test\app.ini")
Do While reader2.Peek() >= 0
Dim line2 = reader2.ReadLine
Do Until line2 Is Nothing
'line2 = reader2.ReadLine()
'ComboBox1.Items.Add(line2.ToString)
'Label1.Text = line2
If line2 <> Nothing Then
If line2.Contains("filename" + a.ToString) Then
Dim values() As String = line2.Split(CChar(":")).ToArray
Dim values2() As String = values(1).Split(CChar(";")).ToArray() 'full filename
Dim values3() As String = values(2).Split(CChar(";")).ToArray() 'keyword to be replaced in filename
Dim values4() As String = values(3).Split(CChar(";")).ToArray() 'fullname in place of keyword
Dim values5() As String = values(4).Split(CChar(";")).ToArray 'destination drive letter
Dim values6() As String = values(5).Split(CChar(";")).ToArray 'destination path after drive letter
ComboBox1.Items.Add(values2(0))
ComboBox1.Items.Add(values3(0))
ComboBox1.Items.Add(values4(0))
ComboBox1.Items.Add(values5(0) + ":" + values6(0))
'Label1.Text = dra.Name.ToString
If dra.Name.ToString.Contains(values2(0)) Then
Dim n As String = dra.Name.Replace(values3(0), values4(0))
File.Copy(dra.FullName, values5(0) + ":" + values6(0) + n)
End If
End If
End If
Exit Do
Loop
a = a + 1
Loop
reader2.Close()
End Using
b = b + 1
Next
Label1.Text = b
Else
MsgBox("No files!")
End
End If
ouput image:
Above image is to show the output and error, first line is the filename1 and the next 8 lines are the output of the app.ini file. As you can see as soon as the filename1 changes to the next file name i.e. Autorun.inf in the 9th line of the above image the same 8 lines of app.ini(line 2nd to 9th in the above image) should be reiterated after Autorun.inf file name but app.ini is not getting to read after file name increments to Autorun.inf and then to FreeSoftware(JF).htm.
The only difference between the first and the second file are the a and b values.
On the first run a will start from 1 and it will be incremented for each line in the app.ini file. After reading 8 lines, the final value of a will be 9.
For the second file, the value a isn't reset so it's value will still be 9. This means that the following condition will never be true because the first run only found value from 1 to 8 *.
If line2.Contains("filename" + a.ToString) Then
To fix your issue, you must set the a variable value back to 1 between each file:
Using reader2 As New IO.StreamReader("D:\Transcend\test\app.ini")
a = 1
Do While reader2.Peek() >= 0
* I'm assuming that the filename in your .ini file are sorted (i.e. line containing filename9 isn't listed before filename2) and that no external process changed the content of your .ini file between the first and the second file.

Find most recent fileS, return the last x number of files IF made within a minute of each other

The situation I'm in is the following:
I need to return the path of the most recent fileS in a folder. The number of files that I need to return is specified by "numberOfFiles" and is in descending order from most recent.
E.g,
File1.doc - Last modified at 8:42:00 PM
File2.doc - Last modified at 8:43:00 PM
File3.doc - Last modified at 8:44:00 PM
numberOfFiles = 2, should return an array of;
File3.doc's path
File2.doc's path
This much is working, with the code below.
Option Explicit
Sub test()
Dim FileName As String
Dim FileSpec As String
Dim MostRecentFile As String
Dim MostRecentDate As Date
Dim Directory As String
Dim resultArray() As String
Dim groupedArray() As String
Dim fileCounter As Integer
Dim groupedArrayCounter As Integer
Dim resultArrayCounter As Integer
Dim i As Integer
Dim numberOfFiles As Integer: numberOfFiles = 2
Directory = "C:\Test\"
FileSpec = "File*.doc"
If Right(Directory, 1) <> "\" Then Directory = Directory & "\"
fileCounter = 0
FileName = Dir(Directory & FileSpec, 0)
If FileName <> "" Then
MostRecentFile = FileName
MostRecentDate = FileDateTime(Directory & FileName)
Do While FileName <> ""
If FileDateTime(Directory & FileName) > MostRecentDate Then
MostRecentFile = FileName
MostRecentDate = FileDateTime(Directory & FileName)
ReDim Preserve resultArray(fileCounter)
resultArray(fileCounter) = FileName
fileCounter = fileCounter + 1
End If
FileName = Dir()
Loop
End If
groupedArrayCounter = 0
resultArrayCounter = UBound(resultArray)
ReDim groupedArray(numberOfFiles - 1)
For i = numberOfFiles To 1 Step -1
groupedArray(groupedArrayCounter) = resultArray(resultArrayCounter)
groupedArrayCounter = groupedArrayCounter + 1
resultArrayCounter = resultArrayCounter - 1
Next i
MsgBox "Done"
End Sub
One last requirement has been put on at the last minute, and I'm not sure how I can achieve it. While I need to be able to return numberOfFiles amount of the most recent files (which works), I must only do so if the files are modified within 60 seconds or less of each other (This also needs to be done in descending order from the most recent - in this example, File3). For example;
If file 2 is made within 60 seconds of file 3, add it to the final array
If file 1 is made within 60 seconds of file 2, add it to the final array
Etc until there are no more files or we have exceeded numberOfFiles
Help greatly appreciated
Edit:
I know this can be done somehow using DateDiff("s", var1, var2), I'm just not entirely sure how the logic will work going in descending order starting from the uBound of my array