Two streams of writing to file - c#

When the writing starts from one file to the resulting file, the entry passes, and from the second file to this result file is blocked. So in two streams record can not be available in the same time. Error: a process can not access a file because this file is being used by another process. How I can resolve this problem. I tried diffrent ways. For example, If you write directly not to a file from two streams, but add string to some array, and then at the end go through the array and write everything to a file. It must be without synschronized.
class Program
{
public static void WriteOneThread()
{
List<char> listOfChars = new List<char>();
FileInfo file = new FileInfo(#"C:\test\task.txt");
FileStream stream = file.Open(FileMode.Open, FileAccess.ReadWrite);
StreamReader reader = new StreamReader(stream);
string str = reader.ReadToEnd();
Console.WriteLine(str);
char[] arr = str.ToCharArray();
for (int i = 0; i < arr.Length; i++)
{
listOfChars.Add(arr[i]);
}
Console.WriteLine(new string('-', 20));
FileInfo file2 = new FileInfo(#"C:\test\Result.txt");
try
{
foreach (var value in listOfChars)
{
StreamWriter writer = file2.CreateText();
writer.WriteLine(value);
writer.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public static void WriteSecondThread()
{
List<char> listOfChars = new List<char>();
FileInfo file = new FileInfo(#"C:\test\pretask.txt");
FileStream stream = file.Open(FileMode.Open, FileAccess.ReadWrite);
StreamReader reader = new StreamReader(stream);
string str = reader.ReadToEnd();
Console.WriteLine(str);
char[] arr = str.ToCharArray();
for (int i = 0; i < arr.Length; i++)
{
listOfChars.Add(arr[i]);
}
Console.WriteLine(new string('-', 20));
FileInfo file2 = new FileInfo(#"C:\test\Result.txt");
try
{
foreach (var value in listOfChars)
{
StreamWriter writer = file2.CreateText();
writer.WriteLine(value);
writer.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static void Main(string[] args)
{
Thread threadOne = new Thread(WriteOneThread);
Thread threadSecond = new Thread(WriteSecondThread);
threadOne.Start();
Thread.Sleep(10000);
threadSecond.Start();
threadOne.Join();
threadSecond.Join();
Console.WriteLine("Запись в файл осуществлена");
Console.ReadKey();
}
}

Related

How do I use a variable outside the scope? (Error: CS0136)

I wrote a program that reads a PDF file and then shows some information about it. It works fine.
class Program
{
static void Main(string[] args)
{
//some variables
string plabels = null;
string text2Search = "IX";
PdfReader reader = new PdfReader("file.pdf");
string[] labels = PdfPageLabels.GetPageLabels(reader);
for (int l = 0; l < labels.Length; l++)
{
plabels += labels[l] + "\n";
}
Console.WriteLine(plabels.IndexOf(text2Search, StringComparison.CurrentCultureIgnoreCase));
Console.ReadLine();
}
}
I also wrote another program that reads a PDF file and makes a copy of it. It also works fine.
class Program
{
static void Main(string[] args)
{
byte[] bytes;
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("file.pdf"))
{
using (var stamper = new PdfStamper(reader, ms))
{
}
}
//grab the bytes before closing things out
bytes = ms.ToArray();
}
File.WriteAllBytes("output.pdf", bytes);
}
}
What I cannot do is to combine these two programs into one.
EDIT
Thanks to your comments I spotted an error. Now my code compiles fine, but when run it gives "Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object." The error point to line for(int l = 0; l < labels.Length; l++).
class Program
{
static void Main(string[] args)
{
byte[] bytes;
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader("file.pdf"))
{
//some variables
string plabels = null;
string text2Search = "IX";
string[] labels = PdfPageLabels.GetPageLabels(reader);
for(int l = 0; l < labels.Length; l++)
{
plabels += labels[l] + "\n";
}
Console.WriteLine(plabels.IndexOf(text2Search, StringComparison.CurrentCultureIgnoreCase));
Console.ReadLine();
using (var stamper = new PdfStamper(reader, ms))
{
}
}
//grab the bytes before closing things out
bytes = ms.ToArray();
}
File.WriteAllBytes("output.pdf", bytes);
}
}
reader is already defined in the using statement. You cannot re-use that variable name inside the using block. Change the name of one of the reader variables or get rid of it.
using (PdfReader reader = new PdfReader("file.pdf"))
{
PdfReader reader = new PdfReader("file.pdf"); //is redundant.
}
labels is null. Your PdfPageLabels.GetPageLabels(reader);
is not returning a value so look in there. No code is posted so I can't give you a clearer answer.

C# ZipArchive losing data

I'm trying to copy the contents of one Excel file to another Excel file while replacing a string inside of the file on the copy. It's working for the most part, but the file is losing 27 kb of data. Any suggestions?
public void ReplaceString(string what, string with, string path) {
List < string > doneContents = new List < string > ();
List < string > doneNames = new List < string > ();
using(ZipArchive archive = ZipFile.Open(_path, ZipArchiveMode.Read)) {
int count = archive.Entries.Count;
for (int i = 0; i < count; i++) {
ZipArchiveEntry entry = archive.Entries[i];
using(var entryStream = entry.Open())
using(StreamReader reader = new StreamReader(entryStream)) {
string txt = reader.ReadToEnd();
if (txt.Contains(what)) {
txt = txt.Replace(what, with);
}
doneContents.Add(txt);
string name = entry.FullName;
doneNames.Add(name);
}
}
}
using(MemoryStream zipStream = new MemoryStream()) {
using(ZipArchive newArchive = new ZipArchive(zipStream, ZipArchiveMode.Create, true, Encoding.UTF8)) {
for (int i = 0; i < doneContents.Count; i++) {
int spot = i;
ZipArchiveEntry entry = newArchive.CreateEntry(doneNames[spot]);
using(var entryStream = entry.Open())
using(var sw = new StreamWriter(entryStream)) {
sw.Write(doneContents[spot]);
}
}
}
using(var fileStream = new FileStream(path, FileMode.Create)) {
zipStream.Seek(0, SeekOrigin.Begin);
zipStream.CopyTo(fileStream);
}
}
}
I've used Microsoft's DocumentFormat.OpenXML and Excel Interop, however, they are both lacking in a few main components that I need.
Update:
using(var fileStream = new FileStream(path, FileMode.Create)) {
var wrapper = new StreamWriter(fileStream);
wrapper.AutoFlush = true;
zipStream.Seek(0, SeekOrigin.Begin);
zipStream.CopyTo(wrapper.BaseStream);
wrapper.Flush();
wrapper.Close();
}
Try the process without changing the string and see if the file size is the same. If so then it would seem that your copy is working correctly, however as Marc B suggested, with compression, even a small change can result in a larger change in the overall size.

How do I zip files in Xamarin for Android?

I have a function that creates a zip file a string array of files passed. The function does succeed in creating the zip file and the zip entry files inside it, but these zip entry files are empty. I've tried a couple of different methods - the function code below is the closest I've gotten to something working:
public static bool ZipFile(string[] arrFiles, string sZipToDirectory, string sZipFileName)
{
if (Directory.Exists(sZipToDirectory))
{
FileStream fNewZipFileStream;
ZipOutputStream zos;
try {
fNewZipFileStream = File.Create(sZipToDirectory + sZipFileName);
zos = new ZipOutputStream(fNewZipFileStream);
for (int i = 0; i < arrFiles.Length; i++) {
ZipEntry entry = new ZipEntry(arrFiles[i].Substring(arrFiles[i].LastIndexOf("/") + 1));
zos.PutNextEntry(entry);
FileStream fStream = File.OpenRead(arrFiles[i]);
BufferedStream bfStrm = new BufferedStream(fStream);
byte[] buffer = new byte[bfStrm.Length];
int count;
while ((count = bfStrm.Read(buffer, 0, 1024)) != -1) {
zos.Write(buffer);
}
bfStrm.Close();
fStream.Close();
zos.CloseEntry();
}
zos.Close();
fNewZipFileStream.Close();
return true;
}
catch (Exception ex)
{
string sErr = ex.Message;
return false;
}
finally
{
fNewZipFileStream = null;
zos = null;
}
}
else
{
return false;
}
}
I think it's got to do with the byte stream handling. I've tried this bit of code that handles the stream but it goes into an infinite loop:
while ((count = fStream.Read(buffer, 0, 1024)) != -1) {
zos.Write(buffer, 0, count);
}
fStream.Close();
I found a solution that is quite simple - I used the ReadAllBytes method of the static File class.
ZipEntry entry = new ZipEntry(arrFiles[i].Substring(arrFiles[i].LastIndexOf("/") + 1));
zos.PutNextEntry(entry);
byte[] fileContents = File.ReadAllBytes(arrFiles[i]);
zos.Write(fileContents);
zos.CloseEntry();
Using Read() on a FileStream returns the amount of bytes read into the stream or 0 if the end of the stream has been reached. It will never return a value of -1.
From MSDN:
The total number of bytes read into the buffer. This might be less than the number of bytes requested if that number of bytes are not currently available, orzero if the end of the stream is reached.
I'd modify your code to the following:
System.IO.FileStream fos = new System.IO.FileStream(sZipToDirectory + sZipFileName, FileMode.Create);
Java.Util.Zip.ZipOutputStream zos = new Java.Util.Zip.ZipOutputStream(fos);
byte[] buffer = new byte[1024];
for (int i = 0; i < arrFiles.Length; i++) {
FileInfo fi = new FileInfo (arrFiles[i]);
Java.IO.FileInputStream fis = new Java.IO.FileInputStream(fi.FullName);
ZipEntry entry = new ZipEntry(arrFiles[i].Substring(arrFiles[i].LastIndexOf("/") + 1));
zos.PutNextEntry(entry);
int count = 0;
while ((count = fis.Read(buffer)) > 0) {
zos.Write(buffer, 0, count);
}
fis.Close();
zos.CloseEntry();
}
This is nearly identical to the code I've used for creating zip archives on Android in the past.
Are you allowed to use SharpZip? It's really easy to use.
Here is a blog post I wrote to extract zip files
private static void upzip(string url)
{
WebClient wc = new WebClient();
wc.DownloadFile(url, "temp.zip");
//unzip
ZipFile zf = null;
try
{
zf = new ZipFile(File.OpenRead("temp.zip"));
foreach (ZipEntry zipEntry in zf)
{
string fileName = zipEntry.Name;
byte[] buffer = new byte[4096];
Stream zipStream = zf.GetInputStream(zipEntry);
using (FileStream streamWriter = File.Create( fileName))
{
StreamUtils.Copy(zipStream, streamWriter, buffer);
}
}
}
finally
{
if (zf != null)
{
zf.IsStreamOwner = true;
zf.Close();
}
}
}
private void ZipFolder(string[] _files, string zipFileName)
{
using var memoryStream = new MemoryStream();
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach (var item in _files)
{
var demoFile = archive.CreateEntry(Path.GetFileName(item));
using var readStreamW = File.OpenRead(item);
using (var entryStream = demoFile.Open())
{
using (var streamWriter = new StreamWriter(entryStream))
{
readStreamW.Seek(0, SeekOrigin.Begin);
readStreamW.CopyTo(streamWriter.BaseStream);
}
}
}
}
using var fileStream = new FileStream(zipFileName, FileMode.Create);
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(fileStream);
}

can we create a clone object of streamreader class in c#?

How can I create a clone object of streamreader, when i do Serializing on streamreader object, program give me exception :
Unhandled Exception: System.Runtime.Serialization.SerializationException: Type '
System.IO.FileStream' in Assembly 'mscorlib, Version=4.0.0.0, Culture=neutral,
is not marked as serializable.
how can i do this?
suppose i have text file like with the text:
1
2
3
4
5
my program:
[Serializable()]
class Program
{
static void Main(string[] args)
{
Program obj = new Program();
obj.read();
}
void read()
{
StreamReader reader1 = new StreamReader(#"d:\test.txt");
string s = reader1.ReadLine();
Console.WriteLine(s);
SerializeObject("text.txt", reader1);
StreamReader reader2;
for (int i = 0; i < 3; i++)
{
reader1.ReadLine();
}
s = reader1.ReadLine();
Console.WriteLine(s);
reader2 = DeSerializeObject("text.txt");
s = reader2.ReadLine();
Console.WriteLine(s);
}
public void SerializeObject(string filename, StreamReader objectToSerialize)
{
Stream stream = File.Open(filename, FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, objectToSerialize);
stream.Close();
}
public StreamReader DeSerializeObject(string filename)
{
StreamReader objectToSerialize;
Stream stream = File.Open(filename, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
objectToSerialize = (StreamReader)bFormatter.Deserialize(stream);
stream.Close();
return objectToSerialize;
}
}
I want to output must be:
1
5
2
OK, so you are simply trying to read a file and write to a different file. There is no serialization involved in what you are trying to do. Serialization generally involves persisting objects.
I believe this is what you are after:
static void Main()
{
using(StreamReader reader = new StreamReader(#"d:\input.txt"))
using(StreamWriter writer = new StreamWriter(#"d:\output.txt"))
{
string line;
// Write 1st line
line = reader.ReadLine();
writer.WriteLine(line);
// Skip 3 lines
for (int i = 0; i < 3; i++)
{
reader.ReadLine();
}
// Write 5th & 6th line
for (int i = 0; i < 2; i++)
{
line = reader.ReadLine();
writer.WriteLine(line);
}
}
}
UPDATE
Write the first line, then the fifth line, then the second line:
static void Main()
{
using(StreamReader reader = new StreamReader(#"d:\input.txt"))
using(StreamWriter writer = new StreamWriter(#"d:\output.txt"))
{
string line;
// Write first line
line = reader.ReadLine();
writer.WriteLine(line);
// Read the second line
string second = reader.ReadLine(); ;
// Skip 3rd & 4th lines
for (int i = 0; i < 2; i++)
{
reader.ReadLine();
}
// Write 5th line
line = reader.ReadLine();
writer.WriteLine(line);
// Write the 2nd line
writer.WriteLine(second);
}
}

SqlBulkCopy and File Archiving

I have a process that loads data into a sql table from a flat file then needs to immediately move the file to an archive folder.
However when running the code it imports the data but throws and IOException
{"The process cannot access the file because it is being used by another process."}
There appears to be some contention in the process. Where and how should I avoid this?
internal class Program
{
private static void Main(string[] args)
{
string sourceFolder = #"c:\ImportFiles\";
string destinationFolder = #"c:\ImportFiles\Archive\";
foreach (string fileName in Directory.GetFiles(sourceFolder, "*.*"))
{
string sourceFileName = Path.GetFileName(fileName);
string destinationFileName = Path.GetFileName(fileName) + ".arc";
ProcessFile(fileName);
string source = String.Concat(sourceFolder,sourceFileName);
string destination = String.Concat(destinationFolder,destinationFileName);
File.Move(source, destination);
}
}
static void ProcessFile(string fileName)
{
Encoding enc = new UTF8Encoding(true, true);
DataTable dt = LoadRecordsFromFile(fileName, enc, ',');
SqlBulkCopy bulkCopy = new SqlBulkCopy("Server=(local);Database=test;Trusted_Connection=True;",
SqlBulkCopyOptions.TableLock);
bulkCopy.DestinationTableName = "dbo.tblManualDataLoad";
bulkCopy.WriteToServer(dt);
bulkCopy.Close();
}
public static DataTable LoadRecordsFromFile(string fileName, Encoding encoding, char delimeter)
{
DataTable table = null;
if (fileName != null &&
!fileName.Equals(string.Empty) &&
File.Exists(fileName))
{
try
{
string tableName = "DataImport";
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
List<string> rows = new List<string>();
StreamReader reader = new StreamReader(fs, encoding);
string record = reader.ReadLine();
while (record != null)
{
rows.Add(record);
record = reader.ReadLine();
}
List<string[]> rowObjects = new List<string[]>();
int maxColsCount = 0;
foreach (string s in rows)
{
string[] convertedRow = s.Split(new char[] { delimeter });
if (convertedRow.Length > maxColsCount)
maxColsCount = convertedRow.Length;
rowObjects.Add(convertedRow);
}
table = new DataTable(tableName);
for (int i = 0; i < maxColsCount; i++)
{
table.Columns.Add(new DataColumn());
}
foreach (string[] rowArray in rowObjects)
{
table.Rows.Add(rowArray);
}
//Remove Header Row From Import file
DataRow row = table.Rows[0];
row.Delete();
table.AcceptChanges();
}
catch
{
//TODO SEND EMAIL ALERT ON ERROR
throw new Exception("Error in ReadFromFile: IO error.");
}
}
else
{
//TODO SEND EMAIL ALERT ON ERROR
throw new FileNotFoundException("Error in ReadFromFile: the file path could not be found.");
}
return table;
}
}
Your program is likely holding the file open. You should wrap FileStream and StreamReader objects in using statements. This closes those objects when the using block finishes.
The part of your LoadRecordsFromFile function that reads the file should look something like:
...
string tableName = "DataImport";
List<string> rows = new List<string>();
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader reader = new StreamReader(fs, encoding))
{
string record = reader.ReadLine();
while (record != null)
{
rows.Add(record);
record = reader.ReadLine();
}
}
}
...

Categories

Resources