Error while handling multiple txt files - c#

I'm constructing a program to search all .xml inside a folder setted by user (Source folder) and copy all these files to another folder (Destination folder).
My program is able to search all XML within all sub folders from (Source folder), the result returns around 5000 files that are placed on a list, this list is worked later by a function, but he can only work with 31 files, then appears "not responding "and the debugger shows that the program is staying a long time in the execution.
Here is my code:
Button action:
private void btnCopiarSalvar_Click(object sender, EventArgs e)
{
foreach (string name in listFileNames)
{
if (readXML(name ))
{
tbArquivo.Text = name ; //Feedback textbox, tell the current filename
}
}
pbStatus.Increment(50);
cbFinal.Checked = true; //Feedback checkBox, to tell user that the task is over.
}
Function ReadXML
public bool readXML(string name)
{
//foreach (string nome in listaArquivos)
//{ //I tried to the foreach inside, but nothing Works.
try
{
string text = null;
string readBuffer = File.ReadAllText(name);
text = readBuffer.Aggregate(text, (current, b) => current + b);
var encoding = new ASCIIEncoding();
Byte[] textobytes = encoding.GetBytes(text);
if (!File.Exists(destino))
{
string destinoComNomeArquivo = destino + "\\" + Path.GetFileName(nome);
using (FileStream fs = File.Create(destinoComNomeArquivo))
{
foreach (byte textobyte in textobytes)
{
fs.WriteByte(textobyte);
pbProcess.PerformStep();
}
Console.WriteLine("Arquivo gravado " + Path.GetFileName(nome));
}
}
pbProcess.PerformStep();
}
catch (Exception e)
{
Console.WriteLine(e);
}
//}
return true;
}
Error: ContextSwitchDeadlock was detected.
Tried Solution: Disable Managed Debug Assistants.
After disabling the MDA, the programs still only read-copy 31 files (of 5k).

The first thing i recommand is ... don't do that kind of file copy! use the File.Copy function instead.
Try to use this code snipping from MSDN:
void DoCopy(string path)
{
var copytask = new Task(() =>
{
string destinoComNomeArquivo = #"C:\" + Path.GetFileName(path);
DirectoryCopy(path, destinoComNomeArquivo, false);
});
copytask.Start();
}
private void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
var counter = 0;
var maxcounter = files.Count();
while (maxcounter < counter)
{
var item = files.ElementAt(counter).Name;
WriteAsnc(item);
counter++;
}
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
const int _maxwritingprocess = Environment.ProcessorCount;
int _currentwritingtasks;
void WriteAsnc(string filepath)
{
_currentwritingtasks++;
var task = Task.Factory.StartNew(() =>
{
XDocument doc = XDocument.Load(filepath);
doc.Elements().First().Add(new XAttribute("Attribute Name","Attribute Value"));
doc.Save(filepath);
_currentwritingtasks--;
});
if(_currentwritingtasks == _maxwritingprocess)
task.Wait();
_currentwritingtasks--;
}
The next point the ContextSwitchDeadlock is a Threading problem and i thing your pbProcess is the source. What does that Process do i don't see anything of that process and i don't thing it is Impotent for your copy

Related

How to copy specific folder to new folder by clicking a button

One Question about coding (Visual Studio C# Windows form Application) There have Two folder: (Source and Target) and I build 1 button "Copy". In (Source) folder have random folders such "20190401", "20190402", "20190403", "20180401", "20170401" and "20160401". Every these folders have [10] ".txt" files. What is the coding if I only want to copy all "201904**" folders with [3] ".txt" files inside to "Target" folder?
Here my code for now, after I click a button the folder wouldn't copy. I guess there have some problem with this codes and I still not found it until. Hope you guys can help me, thank you.
*namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string FROM_DIR = "C:/Users/Desktop/Source/";
string TO_DIR = "C:/Users/Desktop/Target/";
DirectoryInfo diCopyForm = new DirectoryInfo(FROM_DIR);
DirectoryInfo[] fiDiskfiles = diCopyForm.GetDirectories();
string directname = "201904";
string filename = ".txt";
foreach (DirectoryInfo newfile in fiDiskfiles)
{
try
{
if (newfile.Name == "2019")
{
foreach (DirectoryInfo direc in newfile.GetDirectories())
if (direc.Name.StartsWith(directname))
{
int count = 0;
foreach (FileInfo file in direc.GetFiles())
{
if (file.Name.EndsWith(filename))
{
count++;
}
}
if (count == 3)
{
DirectoryCopy(direc.FullName,Path.Combine(TO_DIR,direc.Name), true);
count = 0;
MessageBox.Show("success");
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException("Source directory does not exist or could not be found: "+ sourceDirName);
}
DirectoryInfo[] dirs = dir.GetDirectories();
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
}
*}
By clicking the button, automatically copy all "201904**" folder and 3 ".txt files in (Source) folder to (target folder).
You didn't say which 3 txt files you want to copy so the code below copies all txt files, please explain how you select the files and I'll edit the code.
const string Source = #"C:\Users\Desktop\Source\";
const string Target = #"C:\Users\Desktop\Target\";
const string StartsWith = "201904";
const string FileType = "txt";
public static void Copy()
{
if (!Directory.Exists(Source)) //Check if the source directory exists
throw new Exception("Source directory is missing!");
Directory.CreateDirectory(Target); //If the target directory doesn't exists it will create one
var Directories = Directory.GetDirectories(Source, $"{StartsWith}*"); //Get directories which match the search pattern
for (int i = 0; i < Directories.Length; i++)
{
DirectoryInfo directory = new DirectoryInfo(Directories[i]);
Directory.CreateDirectory($"{Target}{directory.Name}"); //Create the directory in the target folder
var Files = Directory.GetFiles($"{Source}{directory.Name}", $"*.{FileType}"); //Get files
for (int j = 0; j < Files.Length; j++)
{
FileInfo file = new FileInfo(Files[j]);
File.Copy($"{Source}{directory.Name}" + #"\" + file.Name, $"{Target}{directory.Name}" + #"\" + file.Name); //Copy the file to the target folder
}
}
}
This code selects all directories which start with "201904" and all txt files inside them and copies it to the target folder.
EDIT: Fixed a mistake in the code

Get files from a folder that I have created in Xamarin.Android

I want get all files from an external storage folder(wall_e_imgs)..Here are codes-
public void getImages()
{
var path1 = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath.ToString();
string path = System.IO.Path.Combine(path1, "wall_e_imgs");
//var files= System.IO.Directory.GetFiles(Android.OS.Environment.ExternalStorageDirectory.ToString() + "wall_e_imgs");
//var files = System.IO.Directory.GetFiles(path);
//string path = Android.OS.Environment.ExternalStorageDirectory.ToString() + "/wall_e_imgs";
//File directory=new File(path);
Java.IO.File directory = new Java.IO.File(path);
Java.IO.File[] files = directory.ListFiles();//always count is 0 even though there are lot files there
foreach (var i in files)
{
FileInfo info = new FileInfo(i.Name);
if (info.Name.Contains("Wall_e"))
{
di.Add(new DownloadedImages { Path1 = info.DirectoryName, Name1 = info.FullName });
}
}
}
But it always give 0 files even though there are lot of files.
Try this
var folder = Android.OS.Environment.ExternalStorageDirectory + Java.IO.File.Separator + "yourfoldername";
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
var filesList = Directory.GetFiles(folder);
foreach (var file in filesList)
{
var filename = Path.GetFileName(file);
}
Try something like this:
// Use whatever folder path you want here, the special folder is just an example
string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "wall_e_imgs");
if (Directory.Exists(folderPath))
{
var files = Directory.EnumerateFiles(folderPath);
foreach (var file in files)
{
// Do your stuff
}
}
Please note that this uses the Directory class from System.IO, not Java.IO
ffilelist will contain a list of mp3 files in "/storage/emulated/0/Music/"
string phyle;
string ffilelist = "";
public void listfiles()
{
try
{
var path1 = "/storage/emulated/0/Music/";
var mp3Files = Directory.EnumerateFiles(path1, "*.mp3", SearchOption.AllDirectories);
foreach (string currentFile in mp3Files)
{
phyle = currentFile;
ffilelist = ffilelist + "\n" + phyle;
}
//playpath(phyle); // play the last file found
}
catch (Exception e9)
{
Toast.MakeText(ApplicationContext, "ut oh\n"+e9.Message , ToastLength.Long).Show();
}
}

Making an iso file from a directory using DiscUtils

Iam trying to build an iso file from a directory with discutils. This code works fine with a couple of files but after a while i throws an exception stating that "An object with the same key already exists" at "isoBuilder.AddFile(fileOnIso,br.BaseStream);". I don't understand why this happens can someone please shed some light?
public void AddtoISO(string directory,string isoFile)
{
BinaryReader br;
long bytesRemain = 0;
long totalBytesWritten = 0;
DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);
try
{
foreach (FileInfo file in currentDirToAdd.GetFiles())
{
string fileFullPath = file.FullName;
string fileOnIso = fileFullPath.Substring(fileFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
Console.WriteLine(fileOnIso);
br = new BinaryReader(file.OpenRead());
while(totalBytesWritten < file.Length)
{
bytesRemain = file.Length - totalBytesWritten;
br.ReadBytes(blockSize);
isoBuilder.AddFile(fileOnIso,br.BaseStream);
if(bytesRemain<blockSize)
{
totalBytesWritten += bytesRemain;
totalBytesAdded += bytesRemain;
}
else
{
totalBytesWritten += blockSize;
totalBytesAdded += blockSize;
}
}
itemsAdded++;
totalBytesWritten = 0;
}
foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
{
string folderFullPath = subdir.FullName;
string folderOnIso = folderFullPath.Substring(folderFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
isoBuilder.AddDirectory(folderOnIso);
itemsAdded++;
AddtoISO(subdir.FullName,isoFile,ctoken);
}
isoBuilder.Build(isoFile);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Update
An other possible implementation avoiding streams, the drawback is that it takes too much time (over 30 mins) on a 3GB iso which when built with ultraiso for example, it takes aprox 4 mins.. any ideas?
public void AddtoISO(string directory,string isoFile)
{
try
{
DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);
foreach (FileInfo file in currentDirToAdd.GetFiles())
{
string fileOnHdd = file.FullName;
string fileOnIso = fileOnHdd.Substring(fileOnHdd.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
Console.WriteLine(fileOnIso);
isoBuilder.AddFile(fileOnIso,fileOnHdd);
itemsAdded++;
}
foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
{
itemsAdded++;
AddtoISO(subdir.FullName,isoFile,ctoken);
}
isoBuilder.Build(isoFile);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Update:
The exception is thrown when ever the directory structure is the following:
\boot\boot
It seems like it creates the key for boot directory and when it encounters boot.ext file it falsely thinks that it is a double addition. In other words when the files contains the name of its containing directory.
Test building dsl-4.11.rc1.iso
index.html
boot
boot\isolinux
boot\isolinux\boot.cat
boot\isolinux\boot.msg
boot\isolinux\f2
boot\isolinux\f3
boot\isolinux\german.kbd
boot\isolinux\isolinux.bin
boot\isolinux\isolinux.cfg
boot\isolinux\linux24
boot\isolinux\logo.16
boot\isolinux\minirt24.gz
KNOPPIX
KNOPPIX\KNOPPIX
Problem on KNOPPIX\KNOPPIX
Update 2
At last some progress.. the error is not in any of the given paths but im my assumption that i had to keep calling isobuilder.Addfile() until the filestream has been added to the iso entirely.
I just had to move:
isoBuilder.AddFile(fileOnIso,br.BaseStream);
Before the foreach closing bracket. This way it will no have to be added again and again in the iso.
One final problem is at the line
isoBuilder.Build(isoFile);
Where it complains about the file being closed. I tried to correct it with:
FileInfo fi = new FileInfo(isoFile);
isoBuilder.Build(fi.OpenWrite());
But it didnt help. Please someone give me the final push to solve it.
I know this is very OLD but I thought Id post if anyone else needed help with this in future.
Below is a fast and efficient function I use to build an ISO using DiscUtils.Iso9660
public string CreateIsoImage(string sourceDrive, string targetIso, string volumeName)
{
try
{
var srcFiles = Directory.GetFiles(sourceDrive, "*", SearchOption.AllDirectories);
var iso = new CDBuilder
{
UseJoliet = true,
VolumeIdentifier = volumeName
};
foreach (var file in srcFiles)
{
var fi = new FileInfo(file);
if (fi.Directory.Name == sourceDrive)
{
iso.AddFile($"{fi.Name}", fi.FullName);
continue;
}
var srcDir = fi.Directory.FullName.Replace(sourceDrive, "").TrimEnd('\\');
iso.AddDirectory(srcDir);
iso.AddFile($"{srcDir}\\{fi.Name}", fi.FullName);
}
iso.Build(targetIso);
return "Success";
}
catch (Exception ex)
{
return ex.Message;
}
}
Usage:
var res = CreateIsoImage("D:\\", "C:\\Temp\\MyIsoImage.iso", "MyVolumeName");
MessageBox.Show(res);

C# return full path with GetFiles

Use this code for search files in directory:
FileInfo[] files = null;
string path = some_path;
DirectoryInfo folder = new DirectoryInfo(path);
files = folder.GetFiles("*.*", SearchOption.AllDirectories);
This return only filename and extension (text.exe). How to return full path to file(C:\bla\bla\bla\text.exe)?
If I use Directory.GetFiles("*.*"), this return full path. But if folder contains point in name(C:\bla\bla\test.0.1), result contains path to folder without file:
0 C:\bla\bla\bla\text.exe
1 C:\bla\bla\test.0.1
2 C:\bla\text.exe
etc.
FileInfo contains a FullName property, which you can use to retrieve full path to a file
var fullNames = files.Select(file => file.FullName).ToArray();
Check
This code on my machine:
FileInfo[] files = null;
string path = #"C:\temp";
DirectoryInfo folder = new DirectoryInfo(path);
files = folder.GetFiles("*.*", SearchOption.AllDirectories);
//you need string from FileInfo to denote full path
IEnumerable<string> fullNames = files.Select(file => file.FullName);
Console.WriteLine ( string.Join(Environment.NewLine, fullNames ) );
prints
C:\temp\1.dot
C:\temp\1.jpg
C:\temp\1.png
C:\temp\1.txt
C:\temp\2.png
C:\temp\a.xml
...
Full solution
The solution to your problem might look like this:
string path = #"C:\temp";
DirectoryInfo folder = new DirectoryInfo(path);
var directories = folder.GetDirectories("*.*", SearchOption.AllDirectories);
IEnumerable<string> directoriesWithDot =
directories.Where(dir => dir.Name.Contains("."))
.Select(dir => dir.FullName);
IEnumerable<string> filesInDirectoriesWithoutDot =
directories.Where(dir => !dir.Name.Contains("."))
.SelectMany(dir => dir.GetFiles("*.*", SearchOption.TopDirectoryOnly))
.Select(file => file.FullName);
Console.WriteLine ( string.Join(Environment.NewLine, directoriesWithDot.Union(filesInDirectoriesWithoutDot) ) );
Each FileInfo object has a FullName property.
But if folder contains point in name (C:\bla\bla\test.0.1), result contains path to folder without file
This is an entirely different issue with possibly diffeent answers/workarounds. Can you be more specific?
I cannot reproduce this.
You need to use FileInfo.
Directory.GetFiles("", SearchOption.AllDirectories).Select(file => new FileInfo(file).FullName);
public static IEnumerable<string> GetAllFilesRecursively(string inputFolder)
{
var queue = new Queue<string>();
queue.Enqueue(inputFolder);
while (queue.Count > 0)
{
inputFolder = queue.Dequeue();
try
{
foreach (string subDir in Directory.GetDirectories(inputFolder))
{
queue.Enqueue(subDir);
}
}
catch (Exception ex)
{
Console.Error.WriteLine("GetAllFilesRecursively: " + ex);
}
string[] files = null;
try
{
files = Directory.GetFiles(inputFolder);
}
catch (Exception ex)
{
Console.Error.WriteLine("GetAllFilesRecursively: " + ex);
}
if (files != null)
{
for (int i = 0; i < files.Length; i++)
{
yield return files[i];
}
}
}
}
you can try this :
void GetFiles()
{
DirectoryInfo d= new DirectoryInfo(strFolderPath);
//file extension for pdf
var files = d.GetFiles("*.pdf*");
FileInfo[] subfileInfo = files.ToArray<FileInfo>();
if (subfileInfo.Length > 0)
{
for (int j = 0; j < subfileInfo.Length; j++)
{
bool isHidden = ((File.GetAttributes(subfileInfo[j].FullName) & FileAttributes.Hidden) == FileAttributes.Hidden);
if (!isHidden)
{
string strExtention = th.GetExtension(subfileInfo[j].FullName);
if (strExtention.Contains("pdf"))
{
string path = subfileInfo[j].FullName;
string name = bfileInfo[j].Name;
}
}
}
}
You can use FileSystemInfo.FullName property.
Gets the full path of the directory or file.

Directory.Move doesn't work (file already exist)

I've got main folder:
c:\test
And there I have 2 folders: Movies and Photos.
Photos has three folders with files with the same structure: People, Animals and Buildings. I'm trying this code:
Directory.Move(#"c:\test\Movies", #"c:\test\Test");
I get exception:
File already exists
This method will move content of a folder recursively and overwrite existing files.
You should add some exception handling.
Edit:
This method is implemented with a while loop and a stack instead of recursion.
public static void MoveDirectory(string source, string target)
{
var stack = new Stack<Folders>();
stack.Push(new Folders(source, target));
while (stack.Count > 0)
{
var folders = stack.Pop();
Directory.CreateDirectory(folders.Target);
foreach (var file in Directory.GetFiles(folders.Source, "*.*"))
{
string targetFile = Path.Combine(folders.Target, Path.GetFileName(file));
if (File.Exists(targetFile)) File.Delete(targetFile);
File.Move(file, targetFile);
}
foreach (var folder in Directory.GetDirectories(folders.Source))
{
stack.Push(new Folders(folder, Path.Combine(folders.Target, Path.GetFileName(folder))));
}
}
Directory.Delete(source, true);
}
public class Folders
{
public string Source { get; private set; }
public string Target { get; private set; }
public Folders(string source, string target)
{
Source = source;
Target = target;
}
}
Update:
This is a simpler version with the use of Directory.EnumerateFiles recursively instead of using a stack.
This will only work with .net 4 or later, to us it with an earlier version of .net change Directory.EnumerateFiles to Directory.GetFiles.
public static void MoveDirectory(string source, string target)
{
var sourcePath = source.TrimEnd('\\', ' ');
var targetPath = target.TrimEnd('\\', ' ');
var files = Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories)
.GroupBy(s=> Path.GetDirectoryName(s));
foreach (var folder in files)
{
var targetFolder = folder.Key.Replace(sourcePath, targetPath);
Directory.CreateDirectory(targetFolder);
foreach (var file in folder)
{
var targetFile = Path.Combine(targetFolder, Path.GetFileName(file));
if (File.Exists(targetFile)) File.Delete(targetFile);
File.Move(file, targetFile);
}
}
Directory.Delete(source, true);
}
The destination directory should not already exist - the Directory.Move method creates the destination directory for you.
ProcessStartInfo p = new ProcessStartInfo("cmd", "/c move \"c:\\test\\Movies\" \"c:\\test\Test\\"");
p.WindowStyle = ProcessWindowStyle.Hidden; //hide mode
Process.Start(p);
Is it safe for you to delete the destination folder before copying new contents to it?
Directory.Delete(#"c:\test\test");
Directory.Move(#"c:\test\movies",#"c:\test\test");
The most common 2 reasons why Directory.Move could fail are, if:
It's a different volume (you need to Copy/Delete)
It already exists (doesn't support overwrite by default)
Here is my simple solution for the second problem (overwrite):
public bool MoveDirectory(string sourceDirName, string destDirName, bool overwrite)
{
if (overwrite && Directory.Exists(destDirName))
{
var needRestore = false;
var tmpDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
try
{
Directory.Move(destDirName, tmpDir);
needRestore = true; // only if fails
Directory.Move(sourceDirName, destDirName);
return true;
}
catch (Exception)
{
if (needRestore)
{
Directory.Move(tmpDir, destDirName);
}
}
finally
{
Directory.Delete(tmpDir, true);
}
}
else
{
Directory.Move(sourceDirName, destDirName); // Can throw an Exception
return true;
}
return false;
}
You can use move method directly.
Directory.Move(#"c:\test\Movies\", #"c:\test\Test\");
The folder will be deleted and copied it into Test Folder.

Categories