So I've been working on a program that will find all files from a directory and subdirectories and my application is "freezing" while executing because its single-threaded, but I don't know how to multithread a function with an argument in it. so the use is like getallfiles("C:/Folder") and after this it will add each file in a listbox using the following code.
Private Sub getallfiles(filelocation As String)
Try
For Each item As String In My.Computer.FileSystem.GetFiles(filelocation)
If Path.GetExtension(item) = My.Settings.scanfor & "filter" Then
Me.Invoke(Sub() ListBox1.Items.Add(item))
Me.Invoke(Sub() ListBox1.SelectedIndex = ListBox1.Items.Count - 1)
End If
Next
For Each folder As String In My.Computer.FileSystem.GetDirectories(filelocation)
Me.Invoke(Sub() getallfiles(folder))
Next
Catch ex As Exception
End Try
End Sub
and I'm trying to use Thread1 = New System.Threading.Thread(AddressOf getcache(item))
Error BC30577 'AddressOf' operand must be the name of a method
(without parentheses).
if you know any ways of fixing or doing this, I would be happy to hear your answer
Instead of using the vb file functions try the .net System.IO functions. With Directory.GetFiles("Path of Directory to search", "*.txt", SearchOption.AllDirectories) you can search with an extension filter as the second parameter and the last parameter will search all sub-directories. Don't add your items one by one to the listbox. That would be very slow because the listbox has to redraw on each iteration. The GetFiles function returns an array of Strings. You can add this all at once with the listbox items .AddRange Don't forget to add Imports System.IO at the top of the file.
https://msdn.microsoft.com/en-us/library/ms143316(v=vs.110).aspx
Dim FilesFromDir() As String = Directory.GetFiles("C:\Users\maryo\Documents\TextNotes", "*.txt", SearchOption.AllDirectories)
ListBox3.Items.AddRange(FilesFromDir)
Related
I'm working on a project that requires I iterate through a list of controls on a tabpage to find all of the checkboxes. Then depending on the state of the box (checked or unchecked) select individual variables (filenames) to then perform either a batch rename or delete of files on the filesystem (cb.checked = perform action).
I have managed to create the "for each" for the iteration of the controls (thanks google) but I'm struggling to figure out how to pick the variables. They are all named differently, obviously, as are the checkboxes. Also the checkboxes are statically assigned to the form/tabpage. Here's what I have at the moment.
Public Sub delBut_code(ByRef fname As String)
If (Sanity = 1) Then
For Each cb As Control In Form1.Controls
If TypeOf cb Is CheckBox AndAlso DirectCast(cb,
CheckBox).Checked Then
If My.Computer.FileSystem.FileExists(fname) Then
My.Computer.FileSystem.DeleteFile(fname)
End If
End If
Next
MessageBox.Show("All Actions Completed Successfully")
Else
MessageBox.Show("Please select a File To Delete")
End If
End Sub
and here is an example of some of the variables:
Dim castle As String = selPath & "\zm_castle_loadingmovie.txt"
Dim factory As String = selPath &
"\zm_factory_load_factoryloadingmovie.txt"
Dim island As String = selPath & "\zm_island_loadingmovie.txt"
N.B selpath collects a user entered folder path and can be ignored here
I would really appreciate any pointers.
First, you can do much better with the loop:
Public Sub delBut_code(ByRef fname As String)
If Sanity <> 1 Then
MessageBox.Show("Please select a File To Delete")
Exit Sub
End If
Dim checked = Form1.Controls.OfType(Of CheckBox)().Where(Function(c) c.Checked)
For Each box As CheckBox in checked
Try
'A file not existing is only one reason among many this could fail,
' so it needs to be in a Try/Catch block.
' And once you're using a Try/Catch block anyway,
' the FileExists() check becomes a slow and unnecessary extra trip to the disk.
My.Computer.FileSystem.DeleteFile(fname)
Catch
'Do something here to let the user know it failed for this file
End Try
Next
MessageBox.Show("All Actions Completed")
End Sub
But now you need to know how have the right value in that fname variable. There's not enough information in the question for us to fully answer this, but we can give some suggestions. There a number of ways you could do this:
Set the Tag property in the Checkboxes when you build the string variables. Then fname becomes DirectCast(box.Tag, String).
Inherit a custom control from CheckBox to use instead of a normal Checkbox that has an additional String property for the file name. Set this property when you build the string variables.
Name your string variables in a way that you can derive the string variable name from the CheckBox variable name, and then use a Switch to pick the right string variable from each box.Name.
Keep a Dictionary(Of CheckBox, String) that maps the Checkboxes to the right string values.
But without knowing more context of the application, I hesitate to recommend any of these over the others as best for your situation.
I have a directorry which contains many folders such as folder1,folder2,folder3 etc..which contains sub-directories..In that I have a folder name "special" which contains some files
Now I would like to get all those files based on the name of the sub-directory
Example:
C:\Users\desktop\Myfolder\folder1\special\
C:\Users\desktop\Myfolder\folder2\special\
C:\Users\desktop\Myfolder\folder3\special\
C:\Users\desktop\Myfolder\folder4\special\
Now I need to get all the files from each special folder of all the folder1,folder2,folder3 and folder4 and display them in gridview.
grid1.DataSource = (From p1 In IO.Directory.GetFiles("C:\Users\desktop\Myfolder\", "*", IO.SearchOption.AllDirectories)
Where p1.Contains("\special\"))
grid1.DataBind()
I just worked on your case, and i think the following piece of code will suits your requirement. The given code will drill through the directories and it display the filenames if it is comes under the special directory. Comment me back if i wrongly answered your question.
The procedure,
Private Sub GetFiles(ByVal xPath As String)
Try
If Directory.GetDirectories(xPath).Length > 0 Then
For Each xDir As String In Directory.GetDirectories(xPath)
If Directory.Exists(xDir) Then
GetFiles(xDir)
End If
Next
End If
If Directory.GetFiles(xPath).Length > 0 Then
For Each xDir As String In Directory.GetFiles(xPath)
If UCase(Path.GetDirectoryName(xDir)).EndsWith("SPECIAL") Then
MsgBox(Path.GetFileName(xDir))
End If
Next
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
and the call,
call GetFiles("D:\test")
if your datagridview is datagridview1 and countains two columns and you want to add the name file and last modified here is the solution ..
For Each sDir In Directory.GetDirectories("C:\Users\desktop\Myfolder\", "special", SearchOption.AllDirectories)
For Each File In Directory.GetFiles(sDir)
Dim detailedfile As New IO.FileInfo(File)
DataGridView1.Rows.Add(detailedfile.Name, detailedfile.LastAccessTime)
Next
next
if you want to add more details in the gridview you have just to add more columns and more integers in the DataGridView1.Rows.Add
Hey guys before I was just hiding the parent form, but now when I try to read from the parent file it says it can't because it's already running in a process. I followed some tutorial and it said to go to the project properties and have the application stop running when all the forms are closed.
But now since I did that it says the directory can't be found probably because I am reading the input from the parent form. Anyways here is my code
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" + frmLogin.txtUser.Text))
How should I go about doing this?
Edit:
Private Sub btnHunter_Click(sender As System.Object, e As System.EventArgs) Handles btnHunter.Click
selection = "Hunter"
writeData.classSelection()
End Sub
This is what I have when the button is clicked.
Here is the classSelection sub:
Public Sub classSelection()
If frmClass.selection = "Hunter" Then
writeFile1.WriteLine(frmClass.selection)
End If
If frmClass.selection = "Gatherer" Then
writeFile1.WriteLine(frmClass.selection)
End If
If frmClass.selection = "Farmer" Then
writeFile1.WriteLine(frmClass.selection)
End If
writeFile1.Close()
End Sub
The error points to this line:
If frmClass.selection = "Hunter" Then
Saying part of the file path cannot be found.
If you want to read input textbox in closed parent form, you have to declare public var
Make a new module in your project .. and add this
public sLogin as String
And before you hide or close frmLogin .. add this
sLogin = txtUser.Text
So, you could change your code with
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & sLogin))
matzone has given you a good hint. And to check exactly what your path is, just add a MessageBox using variables :
Dim writePath1 As String
Dim writeFile1 As StreamWriter
writePath1 = "C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & sLogin
If MessageBox.Show(writePath1, "Continue ?", MessageBoxButtons.YesNo) = DialogResult.Yes Then
writeFile1 = New StreamWriter(File.OpenWrite(writePath1))
' ...
writeFile1.Close() ' Very important ! Adrian pointed it out.
End If
^^ and if it works, you can discard the Dialog test or replace it by some test code like If File.Exists(...)
However, I don't understand wether you want to close the parent Form or hide it. It's different !
Closing the parent Form will discard any access to parent Form members, including txtUser.Text.
If you want to close the parent Form, the ChildForm should not be a child of that parent you are trying to close, or you must just hide the parent Form :
frmLogin.Hide() ' Not frmLogin.Close()
If you close frmLogin, frmLogin.txtUser won't be accessible, or use sLogin provided by matzone instead. Alternatively, you should pass frmLogin.txtUser.Text value to a custom property of ChildForm.
Imports System.IO
Public Partial Class ChildForm1
' Inherits System.Windows.Form
' ...
Private _txtUserFile As String
Public WriteOnly Property TxtUserFile() As String
Set(ByVal NewFileName As String)
_txtUserFile = NewFileName
End Set
End Property
Public Sub LoadFile()
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" & txtUserFile))
' ...
writeFile1.Close()
End sub
' ...
End Class
Then use this in parent Form :
MyChildForm.TxtUserFile = Me.txtUser.Text
' Me.Close() ' This will definately KILL Form1 (the parent one)
Me.Hide() ' Always use Hide() until you'll terminate your Application
MyChildForm.Show()
MyChildForm.LoadFile()
^^ but this is not a good code either ! Your problem remains unclear (at least for me)
"Still saying it can't find part of the path", then check the path..
Does the file actually exists ?
Does the path contains glitch ? (use the provided MessageBox test)
Does your account can access that directory ? (Windows configuration and account levels)
Well !
In fact, the problem could be somewhere else.
For example, I was able to reproduce your exception by providing an empty string [""] as the value of, either :
frmLogin.txtUser.Text ' = ""
' or
sLogin ' = ""
' or
txtUserFile ' = ""
In fact, I get the "Could not find a part of the path..." exception because the StreamWriter couldn'd read/write to a File, as I didn't provided a valid FileName for that file. As the filename parameter was an empty string "", the provided path for StreamWriter was just representing a directory instead of a file and an exception was raised.
Now, you should check wether you have a valid path before building a new instance of StreamWriter to get sure you are actually pointing to a File ?
Dim writeFile1 As StreamWriter
Dim MyEntirePath As String = "C:\Users\...\Accounts\" + frmLogin.txtUser.Text
MessageBox.Show(MyEntirePath) ' would be enough to be sure your path is correct
' Some test code here...
If everythingOK then ' create the StreamWriter...
writeFile1 = New StreamWriter(MyEntirePath)
' ...
' ...
Also, it's not a good idea to create your streamwriter, and use it in another part/method of your code. You never known if one day, you'll change your code, and forget to make the link between
Dim writeFile1 As StreamWriter = New StreamWriter(File.OpenWrite("C:\Users\Nick\Documents\Visual Studio 2010\Projects\LoginFixed\Accounts\" + frmLogin.txtUser.Text))
' plus
Private Sub btnHunter_Click(sender As System.Object, e As System.EventArgs)
...
End Sub
' plus
Public Sub classSelection()
...
writeFile1.Close()
End Sub
^^ too much "here and there"...
You'll obviously also get an exception if you try to click btnHunter twice.. I don't know what is the purpose of your code nor how it works, it looks like a game.. But I would use File.Exist(..) checks, create the file before, if none, and put that in a Try/Catch to check if I eventually don't have administrator rights to write to that directory. Otherwise, make a code that allow user to read/write files to a custom folder. Andalso, you have :
Application.StartupPath
^^ Very usefull, like :
Dim MyFilePath As String = Application.StartupPath + "\Datas\MyText.txt"
After two weeks of coding, I usually forget where I put those "C:\blabla.." or "D:\gnagna\" or what classes actually uses those absolute reference paths. I've dropped this way of getting directories long ago since the day I moved to Win7 on another computer and all such applications I developped using that approach was doomed...
I wrote a Windows Forms script that searched for all non-hidden and non-readonly folders in my system. But the script itself, when run initially, runs for like 5 minutes. Subsequent opens take much less time. I was wondering if there is a logical error to it, so as to why its running so very slow.
Private Function FindSubFolders(ByVal dir As DirectoryInfo, ByVal node As TreeNode) As TreeNode
Dim subnode As New TreeNode
For Each folder As DirectoryInfo In dir.GetDirectories()
If (folder.Attributes And FileAttributes.Hidden) <> FileAttributes.Hidden Then
subnode = node.Nodes.Add(folder.FullName, folder.Name)
subnode = FindSubFolders(folder, subnode)
End If
Next
Return subnode
End Function
Private Sub SetFolders_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Is it possible to load this on 1st (initial) form load???
Try
Dim node As TreeNode
If TreeView1.Nodes.Count < 1 Then
For Each drive As String In Directory.GetLogicalDrives
Directory.GetLogicalDrives()
Dim folders As DirectoryInfo = New DirectoryInfo(drive)
If (folders.Attributes And FileAttributes.ReadOnly) <> FileAttributes.ReadOnly Then
node = TreeView1.Nodes.Add(drive, drive)
Try
node = FindSubFolders(folders, node)
Catch ex As Exception
Console.WriteLine(ex.Message)
Continue For
End Try
End If
Next
End If
If Not IsNothing(My.Settings.Folders) Then
If ListBox1.Items.Count < 1 Then
For Each col As String In My.Settings.Folders
ListBox1.Items.Add(col)
Next
End If
Else
My.Settings.Folders = New StringCollection
End If
Catch ex As Exception
Logs.Add("04", ex.Message)
End Try
Logs.Add("01", "Loaded.")
End Sub
Thanks for the help! :)
Here are a few tips:
One thing you can do to speed things up is to make sure the TreeView-control does not have to repaint itself every time you add an item to it.
Before adding any item, run Treeview1.BeginUpdate and after you have added all items run Treeview1.EndUpdate
If possible, get the directories as an array, and use the node.addrange to add a whole range of directiryes at once.
From MSDN:
To maintain performance while items
are added one at a time to the
TreeView, call the BeginUpdate method.
The BeginUpdate method prevents the
control from painting until the
EndUpdate method is called. The
preferred way to add items to a tree
view control is to use the AddRange
method to add an array of tree node
items to a tree view. However, if you
want to add items one at a time, use
the BeginUpdate method to prevent the
TreeView control from painting during
the add operations. To allow the
control to resume painting, call the
EndUpdate method when all the tree
nodes have been added to the tree
view.
Check out this question for a (maybe) more easy way to fetch the subfolders:
Get all folder / directories list in VB.net
Alright, so I need a method that traverses all the forms inside a VB.net project under Visual Studio 2008, and create an array of type form with references to all the forms inside it, so that the array looks like this (pseudocode)
FormsArray() = [Form1, Form2, Form3, Form4]
However, I don't have a clue as to how to begin.
You have to adjust the function to put the result of msgbox in a array
Public Sub getallforms(ByVal sender As Object)
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In sender.GetType().Assembly.GetTypes()
If UCase(t.BaseType.ToString) = "SYSTEM.WINDOWS.FORMS.FORM" Then
MsgBox(t.Name)
End If
Next
End Sub
You must call the function from any form in the application like this (getallforms(me))
Here is how you would do this using Reflection, assuming that the class where you placed this code was in the same assembly that you wanted to iterate over. If not, then you'll need to change the Me.GetType().Assembly in the For Each loop into something else to account for loading the assembly in a different manner.
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.IsSubclassOf(formType) = True Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
Hey this is what I did to get the list of forms in my vb project, how ever this in not in code but you could write system.io code fragment to do just that.
open cmd prompt
go to project folder
run a dir /s/b *.designer.vb >> list.txt
use notepad or sublimetext and edit it to get the list ordered as you like it.
:) hope this helped!
I could not get this version to work:
Dim Forms As New List(Of Form)()
Dim formType As Type = Type.GetType("System.Windows.Forms.Form")
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.IsSubclassOf(formType) = True Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
In VB2010 formType is always Nothing
So I dumped the formType line and simply modified your 'IF' statement to check the BaseType instead. Here is the New Version
Dim Forms As New List(Of Form)()
For Each t As Type In Me.GetType().Assembly.GetTypes()
If t.BaseType.Name = "Form" Then
Forms.Add(CType(Activator.CreateInstance(t), Form))
End If
Next
You need to either write a VS macro or an Addin.
In it, from a DTE or DTE2 instance, you can write:
Public Sub GetForms(ByVal host As DTE2)
Dim project As Project = host.ActiveDocument.ProjectItem.ContainingProject
For Each ce As CodeElement In project.CodeModel.CodeElements
If ce.Kind = vsCMElement.vsCMElementClass Then
Dim cl As CodeClass = CType(ce, CodeClass)
If cl.IsDerivedFrom("System.Windows.Forms) Then
'do something
End If
End If
Next
End Sub
2 options
I would load the actual project file into a XML reader. Then iterate all the nodes looking for all Form SubTypes and store the linked files in an array. If the name of file matches the name of the form class, you can create your FormsArray from that list. Otherwise you have to load each file and look for the public class definition of the file to get the list.
Using Reflection, examine the project using Assembly.GetTypes. Find all the System.Windows.Forms.Form Types and store them in a list. Then write out the Type.Name.