How to merge multiple files into one? - c#

I wrote a code that should read all the files in the directory and save to one. Well, for some reason it only reads one file.
foreach (var file in Directory.GetFiles(directory, "*.*"))
{
foreach (var line in File.ReadAllText(file))
{
File.WriteAllText(#"D:\ee.txt", line.ToString());
}
}

A simple way of finding the files in a Directory and merging the content into 1 new file is explained here.
string contents = string.Empty;
string[] arr = Directory.GetFiles(#"C:\Jay", "*.txt");
foreach (string file in arr)
{
contents = File.ReadAllText(file);
File.AppendAllText(#"C:\Jay\mergedfile.txt", contents, Encoding.Default);
}

Related

Creating a zip archive in C# that preserves folder structure

I'm struggling with creating zip archives and could use some guidance from more experienced coders. I am attempting to create a zip archive of 800 folders and subfolders and about 8,000 files with the following method. This code works in so far that it will create an archive but there is no internal directory structure. All 8,000 files are stored in the zip in a single flat list. Is there a way to do this so that its like a typical zip archive in that the folder structure is also stored in the zip file? I am aware of the ZipFile.CreateFromDirectory() method [which does preserve folder structure] but do not want to use it because it fails in the event that a file is locked. I am also aware that there are other libraries but I'd like to use the C# library if that is possible. Any guidance will be appreciated. Thank you.
{
SearchOption searchOption = SearchOption.AllDirectories;
IEnumerable<string> fileSystem;
fileSystem = Directory.EnumerateFileSystemEntries(_zipRoot, "*.*", searchOption);
using (ZipArchive archive = ZipFile.Open(_zipPath, ZipArchiveMode.Create))
{
foreach (var fPath in fileSystem)
{
try
{
archive.CreateEntryFromFile(fPath,Path.GetFileName(fPath));
}
catch
{
FailedFiles.Add(fPath);
Debug.Log(fPath);
}
}
}
Debug.Log($"{FailedFiles.Count} files failed to archive.");
}```
After reading the thread posted by #mjwills which discusses several approaches, the following code suggested by #Curti works like a charm.
public static void StructuredZip(this ZipArchive archive, string sourceDirName, CompressionLevel compressionLevel = CompressionLevel.Fastest)
{
int fileCount = 0;
int folderCount = 0;
int failedCount = 0;
var folders = new Stack<string>();
folders.Push(sourceDirName);
do
{
var currentFolder = folders.Pop();
folderCount++;
foreach (var item in Directory.GetFiles(currentFolder))
{
try
{
archive.CreateEntryFromFile(item, item.Substring(sourceDirName.Length + 1),
compressionLevel);
fileCount++;
}
catch
{
failedCount++;
}
}
foreach (var item in Directory.GetDirectories(currentFolder))
{
folders.Push(item);
}
}
while (folders.Count > 0);
Debug.Log($"Archived {fileCount} in {folderCount} folders. There were {failedCount} failed files!");
}
}
using (var zip = ZipFile.Open(_zipPath, ZipArchiveMode.Create))
{
zip.StructuredZip(_zipRoot);
}

how to untar all the .tar.bz2 present in subdirectories and create a list of all files

I am trying to recursively parse a directory ,look for .tar.bz2 files in the subdirectories , untar and create a list of all the files inside the tar file,following is the detailed info,how to accomplish this?
path = \\location\tarballfiles\
lets say the following .tar.bz2 files are present inside "path" in the mentioned locations
RA900B\hw.1\cqq-tech-fw-RA900B_hw_2-DATA.3.4-00028-S-1.tar.bz2
CQQ9888\hw.2\cqq-tech-fw-CQQ9888_hw_2-DATA.3.4-00028-S-1.tar.bz2
......
EXPECTED OUTPUT:-
RA900B\hw.1\top.bin
RA900B\hw.1\mtp.bin
CQQ9888\hw.2\test.txt
CQQ9888\hw.2\data.txt
.......
PSEUDO CODE:-
for each subfolder under path(ignore any files)
parse recursively to look for .tar.bz2 files
untar
create a list of all the files
To find your tarball files in a directory, you can use:
string[] files = Directory.GetFiles("\\\\location\\tarballfiles\\", "*.tar.bz2", SearchOption.AllDirectories);
and then recurse the files, open them, untar then and add the files of the tar to a list.
Example (with some pseudo code):
var allFiles = new List<string>();
string[] files = Directory.GetFiles("\\\\location\\tarballfiles\\", "*.tar.bz2", SearchOption.AllDirectories);
foreach (var file in files)
{
// untar
var filesFromTar = file.untar();
foreach (var fileNameFromTar in filesFromTar)
{
allFiles.Add(fileNameFromTar);
}
}
foreach (var allFile in allFiles)
{
Console.WriteLine(allFile);
}

Reading contents from several files and writing to one file

In my application there is a situation like this.Before creating a file, my application search for files in a directory under a particular filename. If any file/files found, then it should read each files contents and write these contents(of each file) to a new file. I have googled many and tried some like this:
string temp_file_format = "ScriptLog_" + DateTime.Now.ToString("dd_MM_yyyy_HH");
string[] files = Directory.GetFiles(path,temp_file_format);
foreach (FileAccess finfo in files)
{
string text = File.ReadAllText(finfo);
}
and
System.IO.DirectoryInfo dir = new DirectoryInfo(path);
System.IO.FileInfo[] files = dir.GetFiles(temp_file_format);
foreach (FileInfo finfo in files)
{
finfo.OpenRead();
}
But all these failed..Can anyone show me an alternative for this?
Is there anything wrong in my temp_file_format string?
It will be nice if I could prepend these contents to the new file. Else also, no worries..
any help would be really appreciated..
This is a compete working implementation that does all of that
without reading everything in memory at one time (which doesn't work for large files)
without keeping any files open for more than the required time
using System.IO;
using System.Linq;
public static class Program {
public static void Main()
{
var all = Directory.GetFiles("/tmp", "*.cpp")
.SelectMany(File.ReadAllLines);
using (var w = new StreamWriter("/tmp/output.txt"))
foreach(var line in all)
w.WriteLine(line);
}
}
I tested it on mono 2.10, and it should work on any .NET 4.0+ (for File.ReadAllLines which is a lazy linewise enumerable)
Here's a short snippet that reads all the files and out puts them to the path outputPath
var lines = from file in Directory.GetFiles(path,temp_file_format)
from line in File.ReadAllLines(file)
select line;
File.WriteAllLines(outputPath, content);
The problem you are having with your code is not really related to reading files but simply trying to use an object as a type it's not. Directory.GetFiles returns an array of string and File.ReadXXX and File.OpenRead expects the path as a string. So you simply need to pass each of the strings returned as the path argument to the appropriate method. The above is one such example. Hope it helps both solve your problem and explain the actually issue with your code
try this:
foreach (FileInfo finfo in files)
{
try
{
using (StreamReader sr = new StreamReader("finfo "))
{
String line = sr.ReadToEnd();
Console.WriteLine(line);
}
}
catch (Exception e)
{
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
}
using (var output = File.Create(outputPath))
{
foreach (var file in Directory.GetFiles(InputPath,temp_file_format))
{
using (var input = File.OpenRead(file))
{
input.CopyTo(output);
}
}
}

how to loop , read and write the folders and subfolders files

I am having a problem writing the files in folders and subfolders .
For Example:- test is the main folder
1) C:\test\
and i want to read and write the subfolder files
2)C:\test\12-05-2011\12-05-2011.txt
3)C:\test\13-05-2011\13-05-2011.txt
4)C:\test\14-05-2011\14-05-2011.txt
My code is:
private void button1_Click(object sender, EventArgs e)
{
const string Path1 = #"C:\test";
DoOnSubfolders(Path1);
try
{
StreamReader reader1 = File.OpenText(Path1);
string str = reader1.ReadToEnd();
reader1.Close();
reader1.Dispose();
File.Delete(Path1);
string[] Strarray = str.Split(new char[] { Strings.ChrW(10) });
int abc = Strarray.Length - 2;
int xyz = 0;
while (xyz <= abc)
}
I am getting an error. The error is
Access to the path 'C:\test' is denied.
Can anyone say me what i need to change in this code?
At first you could flatten your recursive calls by calling DirectoryInfo.GetFiles(string, SearchOption) and setting the SearchOption to AllDirectories.
What's also a common mistake (but not clear from your question) is that a directory needs to be created, before you can create a file. Simply call Directory.CreateDirectory(). And put in the complete path (without filename) into it. It will automatically do nothing if the directory already exists and is also able to create the whole needed structure. So no checks or recursive calls are needed (maybe a try-catch if you don't have write access).
Update
So here is an example that reads in a file, does some conversion on each line and writes the result into a new file. If this works properly the original file will be replaced by the converted one.
private static void ConvertFiles(string pathToSearchRecursive, string searchPattern)
{
var dir = new DirectoryInfo(pathToSearchRecursive);
if (!dir.Exists)
{
throw new ArgumentException("Directory doesn't exists: " + dir.ToString());
}
if (String.IsNullOrEmpty(searchPattern))
{
throw new ArgumentNullException("searchPattern");
}
foreach (var file in dir.GetFiles(searchPattern, SearchOption.AllDirectories))
{
var tempFile = Path.GetTempFileName();
// Use the using statement to make sure file is closed at the end or on error.
using (var reader = file.OpenText())
using (var writer = new StreamWriter(tempFile))
{
string line;
while (null != (line = reader.ReadLine()))
{
var split = line.Split((char)10);
foreach (var item in split)
{
writer.WriteLine(item);
}
}
}
// Replace the original file be the converted one (if needed)
////File.Copy(tempFile, file.FullName, true);
}
}
In your case you could call this function
ConvertFiles(#"D:\test", "*.*")
To recursively walk the sub-folders, you need a recursive function ie. One that calls itself. here is an example that should be enough for you to work with:
static void Main(string[] args)
{
const string path = #"C:\temp\";
DoOnSubfolders(path);
}
private static void DoOnSubfolders(string rootPath)
{
DirectoryInfo d = new DirectoryInfo(rootPath);
FileInfo[] fis = d.GetFiles();
foreach (var fi in fis)
{
string str = File.ReadAllText(fi.FullName);
//do your stuff
}
DirectoryInfo[] ds = d.GetDirectories();
foreach (var info in ds)
{
DoOnSubfolders(info.FullName);
}
}
You need use class Directory info and FileInfo.
DirectoryInfo d = new DirectoryInfo("c:\\test");
FileInfo [] fis = d.GetFiles();
DirectoryInfo [] ds = d.GetDirectories();
Here's a quick one liner to write the contents of all text files in a given directory (and all subdirectories) to the console:
Directory.GetFiles(myDirectory,"*.txt*",SearchOption.AllDirectories)
.ToList()
.ForEach(a => Console.WriteLine(File.ReadAllText(a)));
This code:
const string Path1 = #"C:\test";
StreamReader reader1 = File.OpenText(Path1);
Says open "c:\test" as a text file... The error you're getting is:
Access to the path 'C:\test' is denied
You're getting the error because as you stated above, 'c:\test' is a folder. You can't open folders like they are text files, hence the error...
A basic (full depth search) for files with a .txt extension looks like this:
static void Main(string[] args) {
ProcessDir(#"c:\test");
}
static void ProcessDir(string currentPath) {
foreach (var file in Directory.GetFiles(currentPath, "*.txt")) {
// Process each file (replace this with your code / function call /
// change signature to allow a delegate to be passed in... etc
// StreamReader reader1 = File.OpenText(file); // etc
Console.WriteLine("File: {0}", file);
}
// recurse (may not be necessary), call each subfolder to see
// if there's more hiding below
foreach (var subFolder in Directory.GetDirectories(currentPath)) {
ProcessDir(subFolder);
}
}
Have a look at http://support.microsoft.com/kb/303974 for a start. The secret is Directory.GetDirectories in System.IO.
You have to configure (NTFS) security on the c:\Test folder.
Normally you would have the application run under non-admininstrator account so the account that is running the program should have access.
If you are running on Vista or Windows 7 with UAC, you might be an administrator but you will not be using the administrative (elevated) permissions by default.
EDIT
Look at these lines:
const string Path1 = #"C:\test";
DoOnSubfolders(Path1);
try
{
StreamReader reader1 = File.OpenText(Path1);
That last line is trying to read the FOLDER 'c:\test' as if it was a text file.
You can't do that. What are you trying to accomplish there?

C# - Search for Matching FileNames in a Directory using SearchOption

Background: I'm developing a WinForms application using C# with an OpenFileDialog & FileBrowserDialog that will 1) search for a specific string in the filenames of a specified source directory 2) copy files to consolidated directory 3) convert multiple files from excel to csv files, and then 3) convert all the generated csv files into 1 big csv file using a command line executable
Example: MSDN provides a code example that lists all of the directories and files that begin with the letter "c" in "c:\". at http://msdn.microsoft.com/en-us/library/ms143448.aspx so I based my code on that...
Problem: The code doesn't copy any files to the consolidated folder so I'm pretty sure the search doesn't work.
What should I change on here? It doesn't work :
string files = "*.xlsx";
void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, files))
{
// Is this the file we are looking for?
// check excel files for corp name in the filename.
if (f.Contains(m_sc.get_Corp()))
{
// check if thread is cancelled
if (m_EventStop.WaitOne(0, true))
{
// clean-up operations may be placed here
// ...
// inform main thread that this thread stopped
m_EventStopped.Set();
return;
}
else
{
string path = sDir;
string searchPattern = m_sc.get_Corp();
// A file has been found in this directory
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] directories = di.GetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
foreach (FileInfo file in files)
{
try
{
// Copy each selected xlsx files into the specified TargetFolder
System.IO.File.Copy(FileName, consolidatedFolder + #"\" + System.IO.Path.GetFileName(FileName));
Log("File" + FileName + " has been copied to " + consolidatedFolder + #"\" + System.IO.Path.GetFileName(sourceFileOpenFileDialog.FileName));
// Convert each selected XLSX File to CSV Using the command prompt code...
}
}
}
}
The code you've posted does two separate search loops:
first:
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, files))
{
// Is this the file we are looking for?
// check excel files for corp name in the filename.
if (f.Contains(m_sc.get_Corp()))
{
then within that it also does:
string path = sDir;
string searchPattern = m_sc.get_Corp();
// A file has been found in this directory
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] directories = di.GetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
foreach (FileInfo file in files)
{
In the first one you are looking for files matching m_sc.get_Corp();, in the second one you are lookinf for directories...
In fact... your code (pseudo-code?) makes no sense...
Try:
taking your time
tidying up the code yourself
if you rewrite it slowly and break this into smaller chunks, you might spot what you are doing wrong.
Try cleaning up a bit, below is some code that will put you on the path, I've excluded the CSV conversion and the merge, hopefully you will get the idea.
private void YourFileRoutine(string sourceDirectoryPath, string consolidatedDirectoryPath)
{
var excelFiles = new DirectoryInfo(sourceDirectoryPath).GetFiles().Where(x => x.Extension == ".xlsx");
//Copy all Excel Files to consolidated Directory
foreach (var excelFile in excelFiles)
{
FileInfo copiedFile = excelFile.CopyTo(String.Concat(consolidatedDirectoryPath, excelFile.Name)); // Make sure consolidatedDirectoryPath as a "\" maybe use Path.Combine()?
// ConvertToCSV( Do your CSV conversion here, the Path will be = Path.GetFullPath(copiedFile);
}
// Merge CSV's
var csvFiles = new DirectoryInfo(consolidatedDirectoryPath).GetFiles().Where(x => x.Extension == ".csv");
// SomeMergeMethod that iterates through this FileInfo collection?
}

Categories

Resources