Splitting of text file not working properly in c# - c#

I have requirement of writing to text file.
If the file size exceeds 700MB, create new file & write to it.
I am currently writing data with “|” delimited from database to file & after that check the file size & splitting into multiple files, but the file splits in middle of the line.
It should write till end of line or start that particular line in new file .
I need to write the column names in the first line in the newly splited file.
I am new to c#, could you please suggest me the solution with the sample code.
Please find below code to splitting the file
private static void ReadWriteToFile(string fileNames)
{
string sourceFileName = fileNames;
string destFileLocation = Path.GetDirectoryName(fileNames);
int index = 0;
long maxFileSize = 700 * 1024 * 1024;
byte[] buffer = new byte[65536];
using (Stream source = File.OpenRead(sourceFileName))
{
while (source.Position < source.Length)
{
index++;
string newFileName = Path.Combine(destFileLocation, Path.GetFileNameWithoutExtension(sourceFileName));
newFileName += index.ToString() + Path.GetExtension(sourceFileName);
using (Stream destination = File.OpenWrite(newFileName))
{
while (destination.Position < maxFileSize)
{
int bytes = source.Read(buffer, 0, (int)Math.Min(maxFileSize, buffer.Length));
destination.Write(buffer, 0, bytes);
if (bytes < Math.Min(maxFileSize, buffer.Length))
{
break;
}
}
}
}
}
}
Thanks in advance.
Could you please let me know if there is any alternative best way to do this

Try this, a rewrite of a line file splitter i wrote in my beginning c# times.
(You only have to add the column header as a string in the beginning of a new file.)
private static void SplitAfterMBytes(int splitAfterMBytes, string filename)
{
// Variable for max. file size.
var maxFileSize = splitAfterMBytes * 1048576;
int fileCount = 0;
long byteCount = 0;
StreamWriter writer = null;
try
{
var inputFile = new FileInfo(filename);
var index = filename.LastIndexOf('.');
//get only the name of the file.
var fileStart = filename.Substring(0, index);
// get the file extension
var fileExtension = inputFile.Extension;
// generate a new file name.
var outputFile = fileStart + '_' + fileCount++ + fileExtension;
// file format is like: QS_201101_321.txt.
writer = new StreamWriter(outputFile);
using (var reader = new StreamReader(filename))
{
for (string str; (str = reader.ReadLine()) != null;)
{
byteCount = byteCount + System.Text.Encoding.Unicode.GetByteCount(str);
if (byteCount >= maxFileSize)
{
// max number of bytes reached
// write into the old file, without Newline,
// so that no extra line is written.
writer.Write(str);
// 1. close the actual file.
writer.Close();
// 2. open a new file with number incresed by 1.
outputFile = fileStart + '_' + fileCount++ + fileExtension;
writer = new StreamWriter(outputFile);
byteCount = 0; //reset the counter.
}
else
{
// Write into the old file.
// Use a Linefeed, because Write works without LF.
// like Java ;)
writer.Write(str);
writer.Write(writer.NewLine);
}
}
}
}
catch (Exception ex)
{
// do something useful, like: Console.WriteLine(ex.Message);
}
finally
{
writer.Dispose();
}
}

Related

C# get text from .txt file that's added to the program

In my project i added a .txt file. I need to get the content inside of it, line after line, and slip the lines. I alreaddy have code to slipt the lines and overall handle the content of the .txt file like i want to, ill i need is to acess the content of the added file.
The code i have to handle the text form a txt file in the computer:
public static string[] loc_file = File.ReadAllLines(AppDomain.CurrentDomain.BaseDirectory + "\\loc.txt", Encoding.UTF8);
public static string loc_up = string.Join("|", loc_file);
public static string[] loc_p = loc_up.Split('|');
public static string[] loc = loc_p.Where((c, i) => i % 2 == 0).ToArray<string>();
public static string[] loc_txt = loc_p.Where((c, i) => i % 2 != 0).ToArray<string>();
now, how i think the code for what i need will be:
public string exePath = Application.StartupPath.ToString() + "\\loc.txt";
Stream stream = GetType().Assembly.GetManifestResourceStream(namexe);
string[] a = GetType().Assembly.GetManifestResourceNames();
byte[] bytes = new byte[(int)stream.Length];
stream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes(exePath, bytes);
and then just read the text from the file.
thanks!
EDIT 1:
im making this code on my own, not sure if it will work but ill post annyways, if it ends out working i might be helping someone:
public bool get_file(string file)
{
string filePath = Application.StartupPath.ToString() + file;
if (File.Exists(filePath))
{
try
{
Stream stream = GetType().Assembly.GetManifestResourceStream(file);
string[] a = GetType().Assembly.GetManifestResourceNames();
byte[] bytes = new byte[(int)stream.Length];
stream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes(filePath, bytes);
return true;
}
catch { return false; }
}
else { return false; }
}
EDIT 2:
I just realized that string filePath = Application.StartupPath.ToString() + file;
if (File.Exists(filePath))
will give me error because there is no file at the strat of the , lets call it cycle. So ill remove the part to see if file exists cause it makes no sence, leaving the code to be:
public bool get_file(string file)
{
string filePath = Application.StartupPath.ToString() + file;
try
{
Stream stream = GetType().Assembly.GetManifestResourceStream(file);
string[] a = GetType().Assembly.GetManifestResourceNames();
byte[] bytes = new byte[(int)stream.Length];
stream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes(filePath, bytes);
return true;
}
catch { return false; }
}

How to pass folder hierarchy when creating zip file from memory stream using DotNetZip library

Requirement:
1) creating split zips file in multiple segments(say size - 1 GB/500 MB), so that they can be downloaded through browser. The total zip volume of all the segments could exceed 10 GB
2) the zip content could be multiple files or a folder containing sub folders and files
3) the content of the file are read from Cloud in the form of stream. The meta information for the files(like folder hierarchy) are locally available
I am using DotNetZip library to achieve the task. The code is as following:
long length = default(long);
Stream fileReadStream;
long Space = default(long);
string tempZipFile = string.Empty;
FileZipStatus oldStatue = new FileZipStatus();
byte[] Buffer = new byte[1024 * 1024];
if (zipFileName != null && !zipFileName.ToUpper().EndsWith(".ZIP")) zipFileName += ".zip";
string strTempFolder = "";
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
try
{
strTempFolderPath = tempZipOutPutFilePath + "\\";
string strTempFolderName = DateTime.Now.Ticks.ToString();
strTempFolder = strTempFolderPath + strTempFolderName;
if (userFileList.Count > 0)
{
if (Directory.Exists(strTempFolder))
{
Directory.Delete(strTempFolder);
}
Directory.CreateDirectory(strTempFolder);
}
foreach (UserFile userFile in userFileList)
{
WebResponse response = null;
try
{
WebRequest request = null;
IDictionary<string, object> _dictionary = new Dictionary<string, object>();
/// First
FileSystemEnum fileSysEnum = FileSystemBase.GetFileSystemEnumByStorageId(userFile.StorageId);
IFileSystemLib ifileSystemLocal = FileSystemFactory.GetSpecificInstance(fileSysEnum);
fileReadStream = ifileSystemLocal.GetFile(userFile.FilePath, userFile.GuidName, ref request, ref response, _dictionary);
long filesize = default(long);
long.TryParse(ifileSystemLocal.GetFileContentLength(userFile.FilePath, userFile.GuidName).ToString(), out filesize);
Space = (Space > default(long)) ? (Space + filesize) : filesize;
//Now we have to store the data, so that we must access the file
int dataToRead;
FileStream writeStream = new FileStream(strTempFolder + "\\" + userFile.FileName, FileMode.Create, FileAccess.Write);
while ((dataToRead = fileReadStream.Read(Buffer, 0, Buffer.Length)) > 0)
{
writeStream.Write(Buffer, 0, dataToRead);
}
writeStream.Close();
zip.AddFile(strTempFolder + "\\" + userFile.FileName, userFile.RelativePath);
fileReadStream.Close();
}
catch (Exception ex)
{
LogManager.Trace(ex, "ZIpping Block - ZIPFileName", zipFileName + "File to zip" + userFile.GuidName);
}
finally
{
if (response != null) response.Close();
}
}
}
catch (Exception ex)
{
_currentStatus = FileZipStatus.NotAvailable;
oldStatue = UpdateZipStatus(ObjectZipID, Space, FileZipStatus.Failed);
throw ex;
}
finally
{
}
try
{
zip.Comment = "This zip was created at " + System.DateTime.Now.ToString("G");
zip.MaxOutputSegmentSize = 200 * 1024 * 1024; // 200 mb
zip.Save(strTempFolderPath + "\\" + zipFileName);
oldStatue = UpdateZipStatus(ObjectZipID, Space, FileZipStatus.Available);
length = new FileInfo(strTempFolderPath + "\\" + zipFileName).Length;
_currentStatus = FileZipStatus.Available;
// deleting temp folder
Directory.Delete(strTempFolder, true);
}
catch (Exception ex)
{
_currentStatus = FileZipStatus.NotAvailable;
oldStatue = UpdateZipStatus(ObjectZipID, Space, FileZipStatus.Failed);
length = default(long);
throw ex;
}
}
There are a limitation of the DotNetZip libray used in the above code.
It either needs
a) files saved on disk as input. In that case folder hierarchy information could be passed for each file.
or
2) if stream is passed as input, folder hierarchy information could NOT be passed for file.
I need to pass in the folder hierarchy information for each file as well as read the input from stream. As the zip content could be huge(could exceed 10 GB),
do not want to save the files on temporary storage in web server. Can Anyone help like how to pass folder hierarchy when creating zip file? thanks
i got the solution. here is the code
private void button2_Click(object sender, EventArgs e)
{
using (SqlConnection sqlConn = new SqlConnection(#"Data Source=BBATRIDIP\SQLSERVER2008R2;Initial Catalog=test;Integrated Security=True"))
{
string query = String.Format(#"SELECT [FilePath],[FileName],[FileData] FROM [TestTable]");
SqlCommand cmd = new SqlCommand(query, sqlConn);
cmd.Connection.Open();
System.IO.MemoryStream memStream = null;
ZipFile zip = new ZipFile();
zip.MaxOutputSegmentSize = 1024 * 1024; // 1MB each segment size would be
// the above line would split zip file into multiple files and each file
//size would be 1MB
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
byte[] data = (byte[])reader["FileData"];
memStream = new System.IO.MemoryStream(data);
string strFile = reader["FilePath"].ToString() + "\\" + reader["FileName"].ToString();
ZipEntry ze = zip.AddEntry(strFile, memStream);
}
}
zip.Save(#"e:\MyCustomZip.zip");
memStream.Dispose();
MessageBox.Show("Job Done");
// here u can save the zip in memory stream also there is a overload insteaa of saving in HD
}
}
this approach stores the zip content in memory. Hence, when the zip content is huge, say exceeds 5 GB then then it crashes. Need to write to fileOutputStream mapped to physical file

Split large datafile into multiple file with complete rows

I want to split large data file (5 GB) into multiple files (5 files of 1 GB).
I am using this code:-
string destFileLocation = #"C:\Users\";
int index = 0;
long maxFileSize = 1073741824;
byte[] buffer = new byte[65536];
//int a = buffer.Length;
using (Stream source = File.OpenRead(sourceFileName))
{
try
{
while (source.Position < source.Length)
{
index++;
// Create a new sub File, and read into t
string newFileName = Path.Combine(destFileLocation, Path.GetFileNameWithoutExtension(sourceFileName));
//destinationFile = new StreamWriter(
// string.Format(destinationFileName, fileCounter + 1));
newFileName += "_" + index.ToString() + Path.GetExtension(sourceFileName);
using (Stream destination = File.OpenWrite(newFileName))
{
try
{
while (destination.Position < maxFileSize)
{
int bytes = source.Read(buffer, 0, (int)Math.Min(maxFileSize, buffer.Length));
destination.Write(buffer, 0, bytes);
if (bytes < Math.Min(maxFileSize, buffer.Length))
{
break;
}
}
}
finally
{
destination.Dispose();
destination.Close();
}
}
}
}
finally
{
source.Dispose();
source.Close();
}
}
Now files are splitting between the rows but we need full rows.
Please provide some suggestion.

Unexpected output when reading and writing to a text file

I am a bit new to files in C# and am having a problem. When reading from a file and copying to another, the last chunk of text is not being written. Below is my code:
StringBuilder sb = new StringBuilder(8192);
string fileName = "C:...rest of path...inputFile.txt";
string outputFile = "C:...rest of path...outputFile.txt";
using (StreamReader reader = File.OpenText(fileName))
{
char[] buffer = new char[8192];
while ((reader.ReadBlock(buffer, 0, buffer.Length)) != 0)
{
foreach (char c in buffer)
{
//do some function on char c...
sb.Append(c);
}
using (StreamWriter writer = File.CreateText(outputFile))
{
writer.Write(sb.ToString());
}
}
}
My aim was to read and write to a textfile in a buffered manner. Something that in Java I would achieve in the following manner:
public void encrypt(File inputFile, File outputFile) throws IOException
{
BufferedReader infromfile = null;
BufferedWriter outtofile = null;
try
{
String key = getKeyfromFile(keyFile);
if (key != null)
{
infromfile = new BufferedReader(new FileReader(inputFile));
outtofile = new BufferedWriter(new FileWriter(outputFile));
char[] buffer = new char[8192];
while ((infromfile.read(buffer, 0, buffer.length)) != -1)
{
String temptext = String.valueOf(buffer);
//some changes to temptext are done
outtofile.write(temptext);
}
}
}
catch (FileNotFoundException exc)
{
} // and all other possible exceptions
}
Could you help me identify the source of my problem?
If you think that there is possibly a better approach to achieve buffered i/o with text files, I would truly appreciate your suggestion.
There are a couple of "gotchas":
c can't be changed (it's the foreach iteration variable), you'll need to copy it in order to process before writing
you have to keep track of your buffer's size, ReadBlock fills it with characters which would make your output dirty
Changing your code like this looks like it works:
//extracted from your code
foreach (char c in buffer)
{
if (c == (char)0) break; //GOTCHA #2: maybe you don't want NULL (ascii 0) characters in your output
char d = c; //GOTCHA #1: you can't change 'c'
// d = SomeProcessingHere();
sb.Append(d);
}
Try this:
string fileName = #"";
string outputfile = #"";
StreamReader reader = File.OpenText(fileName);
string texto = reader.ReadToEnd();
StreamWriter writer = new StreamWriter(outputfile);
writer.Write(texto);
writer.Flush();
writer.Close();
Does this work for you?
using (StreamReader reader = File.OpenText(fileName))
{
char[] buffer = new char[8192];
bool eof = false;
while (!eof)
{
int numBytes = (reader.ReadBlock(buffer, 0, buffer.Length));
if (numBytes>0)
{
using (StreamWriter writer = File.CreateText(outputFile))
{
writer.Write(buffer, 0, numBytes);
}
} else {
eof = true;
}
}
}
You still have to take care of character encoding though!
If you dont care about carraign returns, you could use File.ReadAllText
This method opens a file, reads each line of the file, and then adds each line as an element of a string. It then closes the file. A line is defined as a sequence of characters followed by a carriage return ('\r'), a line feed ('\n'), or a carriage return immediately followed by a line feed. The resulting string does not contain the terminating carriage return and/or line feed.
StringBuilder sb = new StringBuilder(8192);
string fileName = "C:...rest of path...inputFile.txt";
string outputFile = "C:...rest of path...outputFile.txt";
// Open the file to read from.
string readText = File.ReadAllText(fileName );
foreach (char c in readText)
{
// do something to c
sb.Append(new_c);
}
// This text is added only once to the file, overwrite it if it exists
File.WriteAllText(outputFile, sb.ToString());
Unless I'm missing something, it appears that your issue is that you're overwriting the existing contents of your output file on each blockread iteration.
You call:
using (StreamWriter writer = File.CreateText(outputFile))
{
writer.Write(sb.ToString());
}
for every ReadBlock iteration. The output of the file would only be the last chunk of data that was read.
From MSDN documentation on File.CreateText:
If the file specified by path does not exist, it is created. If the
file does exist, its contents are overwritten.

Unzipping a file error

I am using the SharpZipLib open source .net library from www.icsharpcode.net
My goal is to unzip an xml file and read it into a dataset. However I get the following error reading the file into a dataset: "Data at the root level is invalid. Line 1, position 1."
I believe what is happening is the unzipping code is not releasing the file for the following reasons.
1.) If I unzip the file and exit the application. When I restart the app I CAN read the unzipped file into a dataset.
2.) If I read in the xml file right after writing it out (no zipping) then it works fine.
3.) If I write the dataset to xml, zip it up, unzip it, then attempt to read it back in I get the exception.
The code below is pretty straight forward. UnZipFile will return the name of the file just unzipped. Right below this call is the call to read it into a dataset. The variable fileToRead is the full path to the newly unzipped xml file.
string fileToRead = UnZipFile(filepath, DOViewerUploadStoreArea);
ds.ReadXml(fileToRead )
private string UnZipFile(string file, string dirToUnzipTo)
{
string unzippedfile = "";
try
{
ZipInputStream s = new ZipInputStream(File.OpenRead(file));
ZipEntry myEntry;
string tmpEntry = String.Empty;
while ((myEntry = s.GetNextEntry()) != null)
{
string directoryName = dirToUnzipTo;
string fileName = Path.GetFileName(myEntry.Name);
string fileWDir = directoryName + fileName;
unzippedfile = fileWDir;
FileStream streamWriter = File.Create(fileWDir);
int size = 4096;
byte[] data = new byte[4096];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0) { streamWriter.Write(data, 0, size); }
else { break; }
}
streamWriter.Close();
}
s.Close();
}
catch (Exception ex)
{
LogStatus.WriteErrorLog(ex, "ERROR", "DOViewer.UnZipFile");
}
return (unzippedfile);
}
Well, what does the final file look like? (compared to the original). You don't show the zipping code, which might be part of the puzzle, especially as you are partially swallowing the exception.
I would also try ensuring everything IDisposable is Dispose()d, ideally via using; also - in case the problem is with path construction, use Path.Combine. And note that if myEntry.Name contains sub-directories, you will need to create them manually.
Here's what I have - it works for unzipping ICSharpCode.SharpZipLib.dll:
private string UnZipFile(string file, string dirToUnzipTo)
{
string unzippedfile = "";
try
{
using(Stream inStream = File.OpenRead(file))
using (ZipInputStream s = new ZipInputStream(inStream))
{
ZipEntry myEntry;
byte[] data = new byte[4096];
while ((myEntry = s.GetNextEntry()) != null)
{
string fileWDir = Path.Combine(dirToUnzipTo, myEntry.Name);
string dir = Path.GetDirectoryName(fileWDir);
// note only supports a single level of sub-directories...
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
unzippedfile = fileWDir; // note; returns last file if multiple
using (FileStream outStream = File.Create(fileWDir))
{
int size;
while ((size = s.Read(data, 0, data.Length)) > 0)
{
outStream.Write(data, 0, size);
}
outStream.Close();
}
}
s.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return (unzippedfile);
}
It could also be that the problem is either in the code that writes the zip, or the code that reads the generated file.
I compared the original with the final using TextPad and they are identical.
Also I rewrote the code to take advantage of the using. Here is the code.
My issue seems to be centered around file locking or something. If I unzip the file quit the application then start it up it will read find.
private string UnZipFile(string file, string dirToUnzipTo)
{
string unzippedfile = "";
try
{
using (ZipInputStream s = new ZipInputStream(File.OpenRead(file)))
{
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
{
string directoryName = dirToUnzipTo;
string fileName = Path.GetFileName(theEntry.Name);
string fileWDir = directoryName + fileName;
unzippedfile = fileWDir;
if (fileName != String.Empty)
{
using (FileStream streamWriter = File.Create(fileWDir))
{
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
}
}
}
}
}
catch (Exception ex)
{
LogStatus.WriteErrorLog(ex, "ERROR", "DOViewer.UnZipFile");
}
return (unzippedfile);
}
This is a lot simpler to do with DotNetZip.
using (ZipFile zip = ZipFile.Read(ExistingZipFile))
{
zip.ExtractAll(TargetDirectory);
}
If you want to decide on which files to extract ....
using (ZipFile zip = ZipFile.Read(ExistingZipFile))
{
foreach (ZipEntry e in zip)
{
if (wantThisFile(e.FileName)) e.Extract(TargetDirectory);
}
}
If you would like to overwrite existing files during extraction:
using (ZipFile zip = ZipFile.Read(ExistingZipFile))
{
zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.OverwriteSilently);
}
Or, to extract password-protected entries:
using (ZipFile zip = ZipFile.Read(ExistingZipFile))
{
zip.Password = "Shhhh, Very Secret!";
zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.OverwriteSilently);
}

Categories

Resources