Renaming multiple files by name - vb.net

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

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

FileInfo returning wrong value?

Okay, so I'm working in VB.NET, manually writing error logs to log files (yes, I know, I didn't make the call). Now, if the files are over an arbitrary size, when the function goes to write out the new error data, it should start a new file with a new file name.
Here's the function:
Dim listener As New Logging.FileLogTraceListener
listener.CustomLocation = System.Configuration.ConfigurationManager.AppSettings("LogDir")
Dim loc As String = DateTime.UtcNow.Year.ToString + DateTime.UtcNow.Month.ToString + DateTime.UtcNow.Day.ToString + DateTime.UtcNow.Hour.ToString + DateTime.UtcNow.Minute.ToString
listener.BaseFileName = loc
Dim logFolder As String
Dim source As String
logFolder = ConfigurationManager.AppSettings("LogDir")
If ex.Data.Item("Source") Is Nothing Then
source = ex.Source
Else
source = ex.Data.Item("Source").ToString
End If
Dim errorFileInfo As New FileInfo(listener.FullLogFileName)
Dim errorLengthInBytes As Long = errorFileInfo.Length
If (errorLengthInBytes > CType(System.Configuration.ConfigurationManager.AppSettings("maxFileSizeInBytes"), Long)) Then
listener.BaseFileName = listener.BaseFileName + "1"
End If
Dim msg As New System.Text.StringBuilder
If String.IsNullOrEmpty(logFolder) Then logFolder = ConfigurationManager.AppSettings("LogDir")
msg.Append(vbCrLf & "Exception" & vbCrLf)
msg.Append(vbTab & String.Concat("App: AppMonitor | Time: ", Date.Now.ToString) & vbCrLf)
msg.Append(vbTab & String.Concat("Source: ", source, " | Message: ", ex.Message) & vbCrLf)
msg.Append(vbTab & "Stack: " & ex.StackTrace & vbCrLf)
listener.Write(msg.ToString())
listener.Flush()
listener.Close()
I have this executing in a loop for testing purposes, so I can see what happens when it gets (say) 10000 errors in all at once. Again, I know there are better ways to handle this systemically, but this was the code I was told to implement.
How can I reliably get the size of the log file before writing to it, as I try to do above?
Well, as with many things, the answer to this turned out to be "did you read your own code closely" with a side order of "eat something, you need to fix your blood sugar."
On review, I saw that I was always checking BaseFileName and, if it was over the arbitrary limit, appending a character and writing to that file. What I didn't do was check to see if that file or, indeed, other more recent files existed. I've solved the issue be grabbing a directory list of all the files matching the "BaseFileName*" argument in Directory.GetFiles and selecting the most recently accessed one. That ensures that the logger will always select the more current file to write to or -if necessary- use as the base-name for another appended character.
Here's that code:
Dim directoryFiles() As String = Directory.GetFiles(listener.Location.ToString(), listener.BaseFileName + "*")
Dim targetFile As String = directoryFiles(0)
For j As Integer = 1 To directoryFiles.Count - 1 Step 1
Dim targetFileInfo As New FileInfo(targetFile)
Dim compareInfo As New FileInfo(directoryFiles(j))
If (targetFileInfo.LastAccessTimeUtc < compareInfo.LastAccessTimeUtc) Then
targetFile = directoryFiles(j)
End If
Next
Dim errorFileInfo As New FileInfo(listener.Location.ToString() + targetFile)
Dim errorLengthInBytes As Long = errorFileInfo.Length

check if a file exists and save a new file with an increment

So I know how to increment. I have the following code working:
Dim startFileName As String = StorageRoot & endFile
Dim endFileName As String = String.Empty
Dim Counter As Integer = 1
Do
Dim myFileInfo As New FileInfo(startFileName)
endFileName = myFileInfo.DirectoryName & IIf(Not myFileInfo.DirectoryName.EndsWith("\"), "\", String.Empty).ToString & _
Path.GetFileNameWithoutExtension(startFileName) & Counter & myFileInfo.Extension
Counter += 1
Loop Until Not IO.File.Exists(endFileName)
endFile = endFileName
This works. But here's my dilemma. Lets say the following files exist:
filename_v1.ext
filename_v2.ext
filename_v3.ext
filename_v4.ext
And then the user deletes one of them, lets say filename_v3.ext
On the next upload with my above logic, I need a way for it to make it v5 and not v3 again. The way it is now, it loops and stops after v2 and creates a v3 again.
Thanks for the help!
You can get an array of all files that match filename_v*.ext from Directory.GetFiles(path, searchPattern).
Dim files As String() = Directory.GetFiles("c:\SomePath", "filename_v*.ext")
Parse out the numbers after _v, order them, then take the highest + 1.

search for filenames in textfiles

I have a powershell script that pulls out lines containing ".html" ".css" and so forth
however what I need is to be able to strip out the entire filename
using a pattern.... the entire pattern is returned example
.........\.html returns
src="blank.html"
my answer came in VB (with a bunch of work and even more research) I wanted to share with you all the results, it's not pretty but it works. is there an easier way?
I have commented the code to help in understanding.
Private Sub find()
Dim reader As StreamReader = My.Computer.FileSystem.OpenTextFileReader(openWork.FileName)
Dim a As String
Dim SearchForThis As String
Dim allfilenames As New System.Text.StringBuilder
Dim first1 As String
Dim FirstCharacter As Integer
'Dim lines As Integer
SearchForThis = txtFind.Text
Do
a = reader.ReadLine 'reader.Readling
If a = "" Then
a = reader.ReadLine
End If
If a Is Nothing Then 'without this check the for loops run with bad data, but I can't check "a" without reading it first.
Else
For FirstCharacter = 2 To a.Length - SearchForThis.Length ' start at 2 to prevent errors in the ")" check
If Mid(a, FirstCharacter, SearchForThis.Length) = SearchForThis Then ' compare the line character by character to find the searchstring
If Mid(a, FirstCharacter - 1, 1) <> ")" Then ' checks for ")" just before the searchstring (a common problem with my .CSS finds)
For y = FirstCharacter To 1 Step -1
If Mid(a, y, 1) = Mid(a, FirstCharacter + SearchForThis.Length, 1) Then ' compares the character after searchstring till I find another one
Dim temp = Mid(a, y + 1, (FirstCharacter + SearchForThis.Length) - 1 - y) ' puts the entire filename into variable "temp"
allfilenames.Append(temp & Chr(13)) 'adds the contents of temp (and a carrage return) to the allfilenames stringbuilder
y = 1
Else
End If
Next
End If
End If
Next
End If
Loop Until a Is Nothing
Document.Text = allfilenames.ToString
reader.Close()
End Sub
(updating for comments... thanks for the input)
each line in the .css search file looks something like this.
addPbrDlg.html:12:<link rel=stylesheet href="swl_styles-5.0o-97581885.css" TYPE="text/css">
addPbrDlg.html:727: html(getFrame(statusFrame).strErrorMessage).css('color','red');
for this I want to return
swl_styles-5.0o-97581885.css
but not return
statusFrame).strErrorMessage).css
basically I want to strip out the file names from HTML code
but if I use a pattern like
.............................\.css
it would return something like
t href="swl_styles-5.0o-97581885.css
Finally... there are some variables that I don't need to worry about (due to my personal situation) like I know that all web pages are ".html" all images are ".gif" there are ".css" and ".js" files as well that I want to pull. But because the designers are extremely consistant I know that there aren't any surprise files (.jpg or .htm)
I can also assume that if there is a single quote after the filename, there will be a single quote before. same with double quote.
Thanks for your input so far... I appreciate your time and knowledge.
You need to use Regex and do something like this
Dim files = Regex.Matches("<your whole file text>", "Your regex pattern");
Your regex pattern will look something like this "\Asrc="".+((\.html)|(\.css))"")". This is probably wrong but when you get that straight follow with
Dim fileList as new List(of String)
For Each file as Match in files
' strip " src=" " and last " " "
fileList.Add(file.Value.Substring(5, file.Value.Length - 6))
Next

replacing inner text of an invalid xml file

I want to replace inner text of the tag of an XML file. The XML file I have is not well formed so we cannot use LINQ-TO-XML. Is there another way to accomplish this?
<conf-start ISO-8601-date="2011-05-31"><day>31</day><month>Jan</month><year>2011</year></conf-start>
Within the XML file I just want to replace Jan to 01.
Note : The month name can change in different files and also the
ISO-8601-date="2011-05-31"
Can change. So basically is it possible to find the expression to replace the above line in an invalid XML file.
i tried this,
Dim filePath As String = TextBox1.Text
Dim directory1 As String = Path.GetDirectoryName(filePath)
Dim split As String() = filePath.Split("\")
Dim parentFolder As String = split(split.Length - 2)
Dim yourXml = XDocument.Load(TextBox1.Text & "\" & parentFolder & ".xml").Root
' Change each monthname to the number of the month
For Each elem In yourXml...<conf-start>.<day>.<month>
elem.Value = DateTime.ParseExact(elem.Value, "MMMM", System.Globalization.CultureInfo.InvariantCulture).Month
Next
' save file
yourXml.Save(TextBox1.Text & "\" & parentFolder & ".xml")
but in some files i get errors such as xlink is an undeclared prefix and in some other files i get different errors
Try This
Dim y = "<conf-start iso-8601-date=""2011-05-31""><day>31</day><month>Jan</month><year>2011</year></conf-start>"
Dim Match = Regex.Match(y, "<month>([^>]*)<\/month>").Groups(1).ToString
Regex.Replace(y, Match, DateTime.ParseExact(Match, "MMM", CultureInfo.CurrentCulture).Month.ToString)
It will give you OP Like
<conf-start iso-8601-date="2011-05-31"><day>31</day><month>01</month><year>2011</year></conf-start>
try this code :
Dim ds As New DataSet
ds.ReadXml("yourXmlFile.xml")
If Not ds Is Nothing Then
ds.Tables("conf-start").Rows(0)("month") = DateTime.ParseExact(ds.Tables(0).Rows(0)("month"), "MMM", CultureInfo.CurrentCulture).Month.ToString
ds.WriteXml("yourXmlFile.xml")
End If