Don't know really how to go about this? I can convert one tif to one pdf. I can convert all tifs in one directory into one pdf. What I want to do is convert a group of tifs based on their lastwriteaccess or createddate or modifieddate.
For example, if I have 7 tifs in one directory where 3 have the same timestamp and 4 have another same timestamp, I want to merge the 3 into one pdf then merge the other 4 into another pdf. I'm kind of stuck on how to approach this. Do I need to create list of all the files then group them or can I merge 3 then go the next group merge those etc, etc, etc using a for each?
The code below is what I'm using to collect the first 5 files:
Dim dir As New DirectoryInfo(tiffPath)
Dim files As List(Of FileInfo) =
dir.GetFiles("*.tif").OrderByDescending(Function(fc)
fc.LastAccessTime).Take(5).ToList
For Each lfi As FileInfo In files
MsgBox(lfi.Name)
Next
It looks like it would be sufficient to bunch files together if their timestamps differ by less than some timespan.
So, if you order the files by their .LastWriteTimeUtc then you can iterate over that list and check how long it was between one and the previous one. If the gap is small then add it to the current list, otherwise start a new list.
I tested the following code on a directory with a random selection of files, so 30 days was an appropriate timespan for that, it looks like maybe two or three seconds would be good for your use:
Option Infer On
Option Strict On
Imports System.IO
Module Module1
''' <summary>
''' Get FileInfos bunched by virtue of having less than some time interval between their consecutive LastWriteTimeUtc when ordered by that.
''' </summary>
''' <param name="srcDir">Directory to get files from.</param>
''' <param name="adjacencyLimit">The allowable timespan to count as in the same bunch.</param>
''' <returns>A List(Of List(Of FileInfo). Each outer list has consecutive LastWriteTimeUtc differences less than some time interval.</returns>
Function GetTimeAdjacentFiles(srcDir As String, adjacencyLimit As TimeSpan) As List(Of List(Of FileInfo))
Dim di = New DirectoryInfo(srcDir)
Dim fis = di.GetFiles().OrderBy(Function(fi) fi.LastWriteTimeUtc)
If fis.Count = 0 Then
Return Nothing
End If
Dim bins As New List(Of List(Of FileInfo))
Dim thisBin As New List(Of FileInfo) From {(fis(0))}
For i = 1 To fis.Count - 1
If fis(i).LastWriteTimeUtc - fis(i - 1).LastWriteTimeUtc < adjacencyLimit Then
thisBin.Add(fis(i))
Else
bins.Add(thisBin)
thisBin = New List(Of FileInfo) From {fis(i)}
End If
Next
bins.Add(thisBin)
Return bins
End Function
Sub Main()
Dim src = "E:\temp"
'TODO: choose a suitable TimeSpan, e.g. TimeSpan.FromSeconds(3)
Dim adjacencyLimit = TimeSpan.FromDays(30)
Dim x = GetTimeAdjacentFiles(src, adjacencyLimit)
For Each b In x
Console.WriteLine("***********")
For Each fi In b
'TODO: merge each fi into a PDF.
Console.WriteLine(fi.Name)
Next
Next
Console.ReadLine()
End Sub
End Module
I suggest two or three seconds because if the files have been stored on a FAT-type (e.g. FAT32 or exFAT, as can be used on USB memory sticks, old disk drives, and such) filesystem then the resolution of the timestamp will have been two seconds.
Related
I have a folder that has a many files in it. somewhat between 1000 and 15000.
I would need to randomly pick 1000 files from this folder and copy it over to another folder.
I know how to get a single random file from a folder by inserting the list of files in an array and then selecting one randomly, but dont know how to get many while avoiding to select the same file twice.
If for example I have 1001 file in my folder, it will have no trouble getting the fist few, but then towards the end, it is very likely to pick a file that has already been copied over and it would take many tries to find for example the last file just by luck...
my first idea was to divide the number of files by 1000. so for example 1500/1000 = 1.5. and then create a random integer between 0 and 1.5. this would return 1. then do the next rand between nth image and nth image * 1.5.
if the folder hast 15000 files, it would pick the first file randomly between 1 and 15, and then between 6 and 30 and so on..
but there must be a smarter solution for this..
any help appreciated
You can order them randomly:
Dim allFiles = Directory.EnumerateFiles("path")
Dim rnd As New Random()
Dim random1000 = From f In allfiles
Order By rnd.Next()
Select f
Take 1000
Dim list = random1000.ToList()
This is using System.Linq
Using indices into the list of files
Private Shared prng As New Random
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ListOfiles() As String = IO.Directory.GetFiles(BasePath)
Dim indices As IEnumerable(Of Integer)
indices = Enumerable.Range(0, ListOfiles.Length).OrderBy(Function() prng.Next).Take(1000)
For Each idx As Integer In indices
Dim fn As String = ListOfiles(idx)
Stop
Next
End Sub
I have a text file called "Games.txt" that looks like this:
Call of Duty: 50
Assasins Creed: 23
Watch Dogs: 140
If i want to know the number of "Assasins Creed" How would I get that?
What i have tried so far:
I have tried finding it by knowing the line, length of the string. Then reading that and removing the first 15 charachters ("Assasins Creed:") That would leave me with: 23. But this is a pretty bad way of doing it, and it needs me to know the exact line.
What would a better solution be?
If you only want to get the values for "Assasins Creed", with Regex, you can do something like this:
Dim contents As String = IO.File.ReadAllText(filePath)
Dim re As New Regex("(Assasins Creed):\s*(\d+)")
Dim m As Match = re.Match(contents)
If m.Success Then
Console.WriteLine($"The number of '{m.Groups(1).Value}' games is {m.Groups(2).Value}.")
End If
Output:
The number of 'Assasins Creed' games is 23.
If you need to retrieve the values for all games, you can adjust the above code to something like this:
Dim contents As String = IO.File.ReadAllText(filePath)
Dim re As New Regex("(.+):\s*(\d+)")
Dim matches As MatchCollection = re.Matches(contents)
For Each m As Match In matches
Console.WriteLine($"The number of '{m.Groups(1).Value}' games is {m.Groups(2).Value}.")
Next
Output:
The number of 'Call of Duty' games is 50.
The number of 'Assasins Creed' games is 23.
The number of 'Watch Dogs' games is 140.
Notes:
Remember to replace filePath with the actual path of your text file.
You need to add Imports System.Text.RegularExpressions at the top of your class in order to be able to use the Regex class.
Getting started in this game can be tricky because lots of people expect beginners to do their own research and understand it before offering a simple solution and explanation as to why it works. Giving an absolute beginner a regex statement looks more like someone flexing their ego than offering assistance, so if you're looking for a solution that a beginner can not only use, but also have a hope of understanding (and possibly utilise again elsewhere in their code), then the split command could be used like this:
If you Import System.IO it be more useful than regular expressions at this stage I believe
'Place this at the top of the code block above the Class statement
Imports System.IO 'This provides access to File.ReadAllLines (Input/Output)
Then you could create a function which retrieves the information you need and returns the result like this:
''' <summary>
''' Returns the game value plus the index in the list
''' </summary>
''' <param name="FilePath">Full path of the file</param>
''' <param name="Game">Name of the game to return</param>
''' <param name="index">(Optional) Index of the position in the list (-1 if not found)</param>
''' <returns></returns>
Function GameValue(ByVal FilePath As String, ByVal Game As String, Optional ByRef Index As Integer = -1) As Integer
'This returns the file as an array of lines
Dim Lines() As String = File.ReadAllLines(FilePath)
'This loop will iterate through each item in the array
For i As Integer = 0 To Lines.Length - 1
'This turns each line into an array of name and value (either side of the colon + space)
Dim Segments() As String = Lines(i).Split({": "}, StringSplitOptions.None)
'This will bypass any blank lines or lines without ": "
If Segments.Length > 1 Then
'This tries to match the first segment against the name of the game
If Segments(0) = Game Then
'This handles a successful match
'Store the index of the position of the game in the list
Index = i
'Convert final value into Integer and return result
Return Convert.ToInt32(Segments(1))
End If
End If
Next i
'If no correct match for Game is found, 0 is returned
Return 0
End Function
When you want to call the function, you can do this from within a button click for example:
Private Sub cmdApply_Click(sender As Object, e As EventArgs) Handles cmdApply.Click
'Specify the filename however you like
Dim f As String = "C:\ProgramData\game.txt"
'Specify the name of game however you like
Dim g As String = "Watch Dogs"
'Start an index at -1 (This will get modified by the function if the result is found)
Dim i As Integer = -1
'Use the function to return process a result (value)
Dim v As Integer = GameValue(f, g, i)
Console.WriteLine("Game: " & g)
Console.WriteLine("Value: " & v)
Console.WriteLine("Index: " & i)
End Sub
Sometimes, simple things can actually be pretty complicated once you really look into how to do it. And like most things, there's always another way to go about it.
If you try this code you should be able to take out a few things:
How to make and use a function
How to add xml tags to functions to make calling them easier to understand
One method of utilising ByRef to affect the value of a variable declared elsewhere (index)
How to read a text file and process its contents
How to split a string into an array for independent processing
How to convert a string into an integer
Things to note:
An error will occur if file path or name does not exist
An error might occur if Game: xys value is not a number
An error will not occur if the line does not contain ": " because we tested for that
In this case, the game name is case sensitive. You could use Game.ToUpper and Segments(0).ToUpper to convert both values to uppercase when checking if they match if you want to remove case sensitivity
Is there a simple solution to select random strings in vb.net? I have a list of about twenty paragraphs where three need to go after each other and I want it to be random. Do I have to create a variable? Or is there a command that can be run on a button click?
One (fairly easy way) to accomplish this would be to have a collection of the paragraphs you want to use, and then use PeanutButter.RandomValueGen from the Nuget package PeanutButter.RandomGenerators (it's open-source too)
RandomValueGen.GetRandomFrom takes a collection of anything and returns a random item from the collection. As a bonus, you can specify a params list of values not to pick, so you can ensure that your paragraphs aren't repeated.
Whilst the library is written in C#, it can obviously be used from any .NET project. There are a lot of other generator methods on RandomValueGen too, if you're interested.
Full disclosure: I'm the author.
If you have a normal list, this should work:
If not, write what kind of list you have.
Dim rn As New Random
Dim selct As String = lst(rn.Next(0, lst.Count - 1))
selct is the output.
Replace lst with your list name.
if you don't want to have a dependency or need to stay on 4.0 for some odd reason or reason X, you can always try this instead
Private rnd As New Random
Public Function GetRandom(input As IEnumerable(Of String), itemToGet As Integer) As List(Of String)
If input.Count < itemToGet Then
Throw New Exception("List is too small")
End If
Dim copy = input.ToList
Dim result As New List(Of String)
Dim item As Integer
While itemToGet > 0
item = rnd.Next(0, copy.Count)
result.Add(copy(item))
copy.RemoveAt(item)
itemToGet -= 1
End While
Return result
End Function
i am a noob, so please take this question with that in mind. Here is very simple piece of code:
Sub main()
{
Dim m_Dictionary as new Dictionary(Of Integer, List(Of String))
Dim workingList as new List(Of String)
Dim workingKey as Integer
Dim keyStash as List(Of Integer)
Dim workingDict as new Dictionary(Of Integer, String)
For i=0 to 9
Do
workingKey = RandomInteger()
Loop While workingList.ContainsKey(workingKey)
For n=0 to 4
workingList.Add(RandomString())
Next
keyStash.Add(workingKey)
workingDict.Add(workingKey, workingList)
Next
' now I just want to play back the generators of random data
For each Key As Integer in keyStash
For each Entry as String in workingDict(Key).Value
Line(Entry)
Next
Next
Instead of everything playing back nicely as one might expect, I am left with a fully accurate stash of keys for the dictionary. However, the values for strings inside each list instance are ALL THE SAME FOR EVERY KEY. Those values are equal to the values in the last loop of random data generation. So instead of playing back 50 uniques entries, it writes out 9 times the last loop. I looked inside - everything looks good. Get this. All lists, collections, hash-tables, all of iterated types and also custom types demonstrate this behavior. I found the solution, but it does not explain anything. Can anyone help explaining this, please!??
The variable that keeps the strings generated by RandomString is created outside the loop. Inside that loop you add continuosly new strings to the same instance and add the same list instance to every new integer key. At the end of the loop every integer key added has its value pointing to the same reference of the list. Of course they are identical....
A first fix to your code could be
Dim m_Dictionary as new Dictionary(Of Integer, List(Of String))
Dim workingKey as Integer
For i=0 to 9
' Internal to the loop. so at each loop you get a new list
' to use for the specific key generated in the current loop
Dim workingList as new List(Of String)
Do
workingKey = RandomInteger()
Loop While m_Dictionary.ContainsKey(workingKey)
For n=0 to 4
workingList.Add(RandomString())
Next
m_Dictionary.Add(workingKey, workingList)
Next
For each k in m_Dictionary
For each Entry in k.Value
' Line(Entry)
Console.WriteLine("Key=" & k.Key & " Values = " & Entry)
Next
Next
Please, remember to use Option Strict ON, the current code treats quietly strings as if they were numbers, and this is not a good practice. Option Strict ON will force you to think twice when you work with different type of data.
I need to select a file from a directory and move to another directory. In order to do that I need to select a file randomly.
I need to select a random file (any ext can be) but I dont know how to use return because I am new to VB.NET. So please give ideas and code.
Like this?
Sub MoveRandomFile(from$, to$)
Static r As New Random
Dim Files = New IO.DirectoryInfo([from]).GetFiles
Dim FileToMove = Files(r.Next(0, Files.Count))
IO.File.Move(FileToMove.FullName, FileToMove.FullName.Replace([from], [to]))
End Sub
Or if you just want to return a random file:
Function GetRandomFile(folder$) As IO.FileInfo
Static r As New Random
Dim Files = New IO.DirectoryInfo(folder).GetFiles
Return Files(r.Next(0, Files.Count))
End Function
The static keyword creates the variable the first time the method is called, and keeps it for the next time.
The reason we need to do that is because the random object uses a seed, like in Minecraft, and this seed is generated using information about the running process. So if you create a new random object each time it will choose the same file each time.