I'm creating a CSV file, I'm using C# and CsvHelper to do so.
My CSV file ends up being 205 lines long each time. I know for certain that it should be creating 240 entries, which is what I want.
It seems to stop creating the CSV file at 205 lines. When running it several times it will produce the same result of 205 entry's. Interestingly the last field it attempts to write is one letter short and I'm not sure why.
Below is the full code.
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using CsvHelper;
using System.IO;
namespace PinGenerator
{
class Program
{
static void Main(string[] args)
{
GeneratePins generatePins = new GeneratePins();
generatePins.Start();
Console.ReadLine();
}
}
public class GeneratePins
{
private Dictionary<string, String> pinNumbers = new Dictionary<string, String>();
private List<String> duplicatePinCheck = new List<string>();
private Random random = new Random();
// Runs the sequence for the generation of TimeSpans & Pin Numbers.
// Stores these into JSON / CSV Files
public void Start()
{
TimeSpan timeSpan = new TimeSpan();
TimeSpan maxTime = TimeSpan.FromHours(2);
TimeSpan currentTimeSpan = TimeSpan.FromSeconds(30);
string currentPin = "0000";
// CSV File Creation
TextWriter textWriter = File.CreateText(#"pinNumber.csv");
var csv = new CsvWriter(textWriter);
while (timeSpan.Duration() < maxTime.Duration())
{
// Create TimeSpan & Pin
timeSpan = timeSpan.Add(currentTimeSpan);
currentPin = RandomNumber();
// Duplicate Check
while (duplicatePinCheck.Contains(currentPin))
{
currentPin = RandomNumber();
}
duplicatePinCheck.Add(currentPin);
// Cache Results
string entryPinNumber = currentPin;
string entryTimeSpan = timeSpan.ToString();
// JSON
pinNumbers.Add(entryTimeSpan, currentPin);
// CSV Creation - Write to CSV File
csv.WriteField(entryTimeSpan);
csv.WriteField(entryPinNumber);
csv.NextRecord();
// CONSOLE
Console.WriteLine(entryPinNumber + " / " + timeSpan.ToString());
}
string json = JsonConvert.SerializeObject(pinNumbers, Formatting.Indented);
// Write to JSON File
using (System.IO.StreamWriter file = File.CreateText(#"pinNumbers.json"))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(file, pinNumbers);
}
Console.WriteLine("Created " + pinNumbers.Count() + " pin numbers.");
}
public string RandomNumber()
{
String result = random.Next(0, 9999).ToString();
result = result.PadLeft(4, '0');
return result;
}
}
}
TextWriter textWriter = File.CreateText(#"pinNumber.csv");
Needed to be changed to
StreamWriter streamWriter = File.CreateText(#"pinNumber.csv");
Related
I am attempting to create code that will write values into a csv file, do some other unrelated code and then later on add an extra value to that line
static void Main(string[] args)
{
int newNumber = 110;
var records = new List<MovieInfo>
{
new MovieInfo {Rating = newNumber, Price = 44},
};
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false,
};
string filePath = #"C:\file\path\go\brrrr";
using (var stream = File.Open(filePath, FileMode.Append))
using (var writer = new StreamWriter(stream))
using (var csv = new CsvWriter(writer, config))
{
csv.WriteRecords(records);
}
//--------------------------------------
//other unrelated code things happen here
//--------------------------------------
double value = 4;
string thirdValue = "," + value;
File.AppendAllText(filePath, thirdValue);
}
public class MovieInfo
{
public int Rating { get; set; }
public int Price { get; set; }
}
The output of this code is this
Output code
Is it possible to adjust the code so that the output will be 110,44,4 instead? Additional info if it is relevant would be that the line in question will always be the last in the file. Any help is appreciated
When you call csv.WriteRecords(records); all records are written to the output file and each record is separated by a newline, even the last record has a new line appended.
Instead of writing every record in one go, you could write a record at time with the WriteRecord method. This method doesn't write the newline.
A new line is added when you call the NextRecord method. So looping on your records minus one you can control the output of the newline on the last line:
void Main()
{
int newNumber = 110;
var records = new List<MovieInfo>
{
new MovieInfo {Rating = 200, Price = 30},
new MovieInfo {Rating = newNumber, Price = 44},
};
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false,
};
string filePath = #"E:\temp\movieinfo.csv";
using (var stream = File.Open(filePath, FileMode.Append))
using (var writer = new StreamWriter(stream))
using (var csv = new CsvWriter(writer, config))
{
// Write all records minus one.
for (int x = 0; x < records.Count - 1; x++)
{
csv.WriteRecord(records[x]);
csv.NextRecord();
}
// Write the last record without the newline
csv.WriteRecord(records[records.Count-1]);
}
//--------------------------------------
//other unrelated code things happen here
//--------------------------------------
double value = 4;
string thirdValue = "," + value;
File.AppendAllText(filePath, thirdValue);
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Homework
{
class Program
{
static void Main(string[] args)
{
string mode = args[0];
string name = args[1];
if(mode == "split")
{
FileInfo fileinfo = new FileInfo(name);
int fileSize = (int)fileinfo.Length;
int partSize = 1024;
int numberOfPart = (int)Math.Ceiling((double)fileSize / partSize);
string chunkName = "";
int byteRemaining = fileSize;
FileStream list = File.OpenWrite(name + "_list");
StreamWriter list_write = new StreamWriter(list, System.Text.Encoding.UTF8);
list_write.WriteLine(name); //list 파일 첫 줄에 원본 파일 이름 저장
Console.WriteLine(name + "_list");
for(int count = 1; count <= numberOfPart; count++)
{
byte[] buffer = new byte[partSize];
chunkName = string.Format("{0}_{1}", name, count);
int chunkSize;
FileStream origin = File.OpenRead(name);
BinaryReader origin_read = new BinaryReader(origin);
if(byteRemaining >= partSize)
{
chunkSize = partSize;
}
else
{
chunkSize = byteRemaining;
}
buffer = origin_read.ReadBytes(chunkSize); //원본 읽기
FileStream chunk = File.OpenWrite(chunkName);
BinaryWriter chunk_write = new BinaryWriter(chunk);
chunk_write.Write(buffer); //chunk에 쓰기
byteRemaining -= chunkSize;
list_write.WriteLine(chunkName); //chunkName도 list 파일에 저장
Console.WriteLine(chunkName);
origin_read.Close();
chunk_write.Close();
}
list_write.Close();
}
else if(mode == "merge")
{
FileStream list = File.OpenRead(name); //list 파일 읽는 스트림
StreamReader list_read = new StreamReader(list, Encoding.Default, true);
string originName = list_read.ReadLine();
FileStream origin = File.OpenWrite(originName); //origin 파일 다시 만드는 스트림
BinaryWriter origin_write = new BinaryWriter(origin);
int partSize = 1024;
while(list_read.EndOfStream == false) //list 파일이 끝날때까지 읽어들임
{
string chunkName = list_read.ReadLine();
byte[] buffer = new byte[partSize];
FileStream chunk = File.OpenRead(chunkName); //각 chunk 읽는 스트림
BinaryReader chunk_read = new BinaryReader(chunk);
FileInfo fileinfo = new FileInfo(chunkName);
buffer = chunk_read.ReadBytes((int)fileinfo.Length); //파일 크기만큼 buffer로 읽어옴
origin_write.Write(buffer); //buffer로 옮긴 내용 원본파일에 쓰기
}
}
Console.ReadKey();
}
}
}
*Expected
split : split file into chunks of 1kb and make [filename]_list file which contain information of name of original file name and name of chunks([filename]_1, [filename]_2 . . .)
merge : read [filename]_list file which created while split process and merge chunks one file again. And after merging, merged file have to be exactly same as original file that we split above.
*Problem
In case of .txt file -> doing well as expected, but in .jpg file, split well but merged file is not same as original file.
Issue:
The issue with your code is that when you split the file into parts/sections, instead of splitting the file into seperate files each containing the next chuck-part of bytes, you splitting the file starting each time from the begining, resulting into the wrong merging file (image demonstrating the issue)
Solution:
So what you only have to do, is just to move out of the for loop 3 specific lines of code such that your code will look like this:
FileStream origin = File.OpenRead(name); // 1st line
BinaryReader origin_read = new BinaryReader(origin); // 2nd line
for (int count = 1; count <= numberOfPart; count++)
{
...
}
origin_read.Close(); //3rd line
list_write.Close();
Recomended solution:
Although, here a recomended solution too.
using System;
using System.IO;
using System.Linq;
namespace Homework
{
class Program
{
static void Main(string[] args)
{
string mode = args[0];
string file = args[1]; // sourcefile or sourcefile_list
try{
switch (mode){
case "split":
byte[] buffer = File.ReadAllBytes(file);
int partSize = 1024;
int numberOfPart = (int)Math.Ceiling((double)buffer.Length / partSize);
string chunkPathName; // The path-and-name of the chunk-file
// go through all parts
for (int count = 0; count < numberOfPart; count++)
{
chunkPathName = file + "_" + (count + 1);
//write all bytes to the destination-chunk file from a specific point and on.... and then "pass"/write the chuck's path-name into the _list file
File.WriteAllBytes(chunkPathName, buffer.Skip(count * partSize).Take(partSize).ToArray());
File.AppendAllText(file + "_list", chunkPathName + "\n");
Console.WriteLine("Splitting: " + chunkPathName);
}
break; // exit switch
case "merge":
// create a stream pointing to your desired-destination/origin-file
var originstream = new FileStream(file.Remove(file.Length - "_list".Length, "_list".Length), FileMode.Create);
Console.WriteLine("destination path = " + file.Remove(file.Length - "_list".Length) + "\n");
// go through each line of the file (_list)
foreach (string _chunkPathName in File.ReadAllLines(file))
{
Console.WriteLine("Merging: " + _chunkPathName);
// read all bytes from chunk and append them into the origin-file
byte[] chunk = File.ReadAllBytes(_chunkPathName);
originstream.Write(chunk, 0, chunk.Length);
}
// close the stream
originstream.Close();
break; // exit switch
}
Console.WriteLine("\n" + mode + " is done!");
}catch (Exception ex){
//code for any other type of exception
}
Console.ReadKey();
}
}
}
i've tried to make it clear enough with comments too..
I don't know C# or any programming that well at all, but I want to learn. I've been searching online last couple days to put together what is supposed to read from 2 text files and output a file (formatted for a json file that I'll just copy/paste into that file). So I can read from two files, create a dictionary object and write to a file but it's only writing the last item. I believe I'm overwriting over and over until the last part. How do I append to the file rather than overwrite?
My code:
using System.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WriteLangFile
{
class Program
{
static void Main(string[] args)
{
try
{
string path1 = #"C:\temp\langVars.txt";
string path2 = #"C:\temp\langValues.txt";
string[] readVars = File.ReadAllLines(path1);
string[] readVals = File.ReadAllLines(path2);
Dictionary<string, string> dictionaryVars = new Dictionary<string, string>();
for (int i = 0; i < readVars.Length; i++)
{
dictionaryVars.Add(readVars[i], readVals[i]);
}
string outputPath = ("C:\\temp\\");
string outputFileName = ("lang.txt");
string constant, value;
foreach (KeyValuePair<string, string> kvp in dictionaryVars)
{
constant = (kvp.Key);
value = (kvp.Value);
string[] lines = { ("\"LANG_\"" + constant + "\"_LANG \"" + " : { "),
("\"translations\" : {"),
("\"Lang.asp\" : {"),
("\"eng\"" + ": \"" + value + "\""),
("}"),
("}"),
("},")
};
using (StreamWriter outFile = new StreamWriter(Path.Combine(outputPath, outputFileName)))
{
foreach (var item in lines)
{
outFile.WriteLine(item.ToString());
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
finally
{
Console.WriteLine("Executing finally block.");
}
}
}
}
Your issue is that you're opening/closing the file within the loop, and you're not using the constructor of StreamWriter that takes the append option.
The best solution is probably to move StreamWriter creation outside of the loop so that you only open the file once:
using (StreamWriter outFile = new StreamWriter(Path.Combine(outputPath, outputFileName)))
{
foreach (KeyValuePair<string, string> kvp in dictionaryVars)
{
constant = (kvp.Key);
value = (kvp.Value);
string[] lines = { ("\"LANG_\"" + constant + "\"_LANG \"" + " : { "),
("\"translations\" : {"),
("\"Lang.asp\" : {"),
("\"eng\"" + ": \"" + value + "\""),
("}"),
("}"),
("},")
};
foreach (var item in lines)
{
outFile.WriteLine(item.ToString());
}
}
}
For completeness, if you were to keep the StreamWriter creation within the loop, you could construct it like this so that it appends rather than overwriting the file:
using (StreamWriter outFile = new StreamWriter(Path.Combine(outputPath, outputFileName), append: true))
P.S. It looks like you might be trying to generate a file with JSON inside it. At present your code does not generate valid JSON. If you want to generate JSON, you should use a serializer such as JSON.NET rather than building the JSON manually (i.e. in an error-prone way).
All I need is for file1 and file2 to show the text inside the file. File1 is working great! File2 not so much. I believe there is something wrong with how I wrote file2 being read. Because I made a class so that I can make file2's text go to another file called outputfile2, and even that isn't working.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
namespace RandomName
{
class Program
{
static void Main(string[] args)
{
string winDir =
"C:/Users/RandomPerson/Desktop/RandomName/bin/Debug/";
string fileName = "file1.txt";
StreamReader reader = new StreamReader(winDir + fileName);
string outputFileName = "upperfile" + fileName;
StreamWriter writer = new StreamWriter(outputFileName);
int n = 0;
string st = "";
string upperString = "";
int n2 = 0;
string st2 = "";
string upperString2 = "";
string fileName2 = "file2.txt";
StreamReader reader2 = new StreamReader(winDir + fileName2);
string outputFileName2 = "output" + fileName2;
StreamWriter writer2 = new StreamWriter(outputFileName2);
do
{
++n;
st = reader.ReadLine(); // read one line from disk file
Console.WriteLine("Line #" + n + ": " + st); // write to the console
writer.WriteLine(st); // write line to disk file instead, using WriteLine() method
upperString = upperString + "\n" + st; // append each line to the big string
}
while (!reader.EndOfStream);
do
{
++n2;
st2 = reader2.ReadLine(); // read one line from disk file
Console.WriteLine("Line #" + n2 + ": " + st2); // write to the
console
writer2.WriteLine(st2); // write line to disk file instead,
using WriteLine() method
upperString2 = upperString2 + "\n" + st2; // append each line
to the big string
}
while (!reader2.EndOfStream);
reader.Close();
writer.Close();
Console.WriteLine("\nHere is the entire file in a string:");
Console.WriteLine(upperString);
Console.WriteLine(upperString2);
UpperString b = new UpperString(upperString);
UpperString2 c = new UpperString2(upperString2);
Console.WriteLine("\nThe string in reverse case: ");
b.showReverseCase();
Console.WriteLine("\n");
c.readingFile2();
c.toNewFile2();
}
}
}
"b." is for another class that I have. I copied the code from that class into the "c." one, changing names of strings and such. And that didn't work. Which is why I think something is wrong somewhere in the main.
Here is the class
class UpperString2
{
private string upperString2;
public UpperString2() { }
public UpperString2(string c) { upperString2 = c; }
public void readingFile2()
{
string[] lines = System.IO.File.ReadAllLines("C:/Users/SomeName/Desktop/FolderName/bin/Debug/file2.txt");
System.Console.WriteLine("\nAnother Poem \n");
foreach (string line in lines)
{
// Use a tab to indent each line of the file.
Console.WriteLine(line);
}
}
public void toNewFile2()
{
using (StreamWriter writetext = new StreamWriter("outputfile2.txt"))
{
string newText = (upperString2.ToUpper()).ToString();
writetext.WriteLine(newText);
}
}
I am a bit new to SteamReader and SteamWriter, which is why I think I went wrong somehow with that. I'm not sure what though. Thank you anyone who can help me have the text in file2 show up without it being overwritten by file1's text!
The problem is "outputfile2" was already opened by reader2 in Main().
string fileName2 = "file2.txt";
StreamReader reader2 = new StreamReader(winDir + fileName2);
string outputFileName2 = "output" + fileName2; //<--outputfile2.txt
StreamWriter writer2 = new StreamWriter(outputFileName2)
Then it raises an exception when you try to open the same file for writting in toNewFile2():
public void toNewFile2()
{
using (StreamWriter writetext = new StreamWriter("outputfile2.txt"))
{
string newText = (upperString2.ToUpper()).ToString();
writetext.WriteLine(newText);
}
}
This happens because the object writer2 is still alive and locking the file in Main() and there's no using statement for disposing the object when no longer needed.
Since you have moved the code to a class, call that class instead.
Firstly, i'd just like to mention that I've only started learning C# a few days ago so my knowledge of it is limited.
I'm trying to create a program that will parse text files for certain phrases input by the user and then output them into a new text document.
At the moment, i have it the program searching the original input file and gathering the selected text input by the user, coping those lines out, creating new text files and then merging them together and also deleting them afterwards.
I'm guessing that this is not the most efficient way of creating this but i just created it and had it work in a logical manor for me to understand as a novice.
The code is as follows;
private void TextInput1()
{
using (StreamReader fileOpen = new StreamReader(txtInput.Text))
{
using (StreamWriter fileWrite = new StreamWriter(#"*DIRECTORY*\FIRSTFILE.txt"))
{
string file;
while ((file = fileOpen.ReadLine()) != null)
{
if (file.Contains(txtFind.Text))
{
fileWrite.Write(file + "\r\n");
}
}
}
}
}
private void TextInput2()
{
using (StreamReader fileOpen = new StreamReader(txtInput.Text))
{
using (StreamWriter fileWrite = new StreamWriter(#"*DIRECTORY*\SECONDFILE.txt"))
{
string file;
while ((file = fileOpen.ReadLine()) != null)
{
if (file.Contains(txtFind2.Text))
{
fileWrite.Write("\r\n" + file);
}
}
}
}
}
private static void Combination()
{
ArrayList fileArray = new ArrayList();
using (StreamWriter writer = File.CreateText(#"*DIRECTORY*\FINALOUTPUT.txt"))
{
using (StreamReader reader = File.OpenText(#"*DIRECTORY*\FIRSTFILE.txt"))
{
writer.Write(reader.ReadToEnd());
}
using (StreamReader reader = File.OpenText(#"*DIRECTORY*\SECONDFILE.txt"))
{
writer.Write(reader.ReadToEnd());
}
}
}
private static void Delete()
{
if (File.Exists(#"*DIRECTORY*\FIRSTFILE.txt"))
{
File.Delete(#"*DIRECTORY*\FIRSTFILE.txt");
}
if (File.Exists(#"*DIRECTORY*\SECONDFILE.txt"))
{
File.Delete(#"*DIRECTORY*\SECONDFILE.txt");
}
}
The output file that is being created is simply outputting the first text input followed by the second. I am wondering if it is possible to be able to merge them into 1 file, 1 line at a time as it is a consecutive file meaning have the information from Input 1 followed 2 is needed rather than all of 1 then all of 2.
Thanks, Neil.
To combine the two files content in an one merged file line by line you could substitute your Combination() code with this
string[] file1 = File.ReadAllLines("*DIRECTORY*\FIRSTFILE.txt");
string[] file2 = File.ReadAllLines("*DIRECTORY*\SECONDFILE.txt");
using (StreamWriter writer = File.CreateText(#"*DIRECTORY*\FINALOUTPUT.txt"))
{
int lineNum = 0;
while(lineNum < file1.Length || lineNum < file2.Length)
{
if(lineNum < file1.Length)
writer.WriteLine(file1[lineNum]);
if(lineNum < file2.Length)
writer.WriteLine(file2[lineNum]);
lineNum++;
}
}
This assumes that the two files don't contains the same number of lines.
try this method. You can receive three paths. File 1, File 2 and File output.
public void MergeFiles(string pathFile1, string pathFile2, string pathResult)
{
File.WriteAllText(pathResult, File.ReadAllText(pathFile1) + File.ReadAllText(pathFile2));
}
If the pathResult file exists, the WriteAllText method will overwrite it. Remember to include System.IO namespace.
Important: It is not recommended for large files! Use another options available on this thread.
If your input files are quite large and you run out of memory, you could also try wrapping the two readers like this:
using (StreamWriter writer = File.CreateText(#"*DIRECTORY*\FINALOUTPUT.txt"))
{
using (StreamReader reader1 = File.OpenText(#"*DIRECTORY*\FIRSTFILE.txt"))
{
using (StreamReader reader2 = File.OpenText(#"*DIRECTORY*\SECONDFILE.txt"))
{
string line1 = null;
string line2 = null;
while ((line1 = reader1.ReadLine()) != null)
{
writer.WriteLine(line1);
line2 = reader2.ReadLine();
if(line2 != null)
{
writer.WriteLine(line2);
}
}
}
}
}
Still, you have to have an idea how many lines you have in your input files, but I think it gives you the general idea to proceed.
Using a FileInfo extension you could merge one or more files by doing the following:
public static class FileInfoExtensions
{
public static void MergeFiles(this FileInfo fi, string strOutputPath , params string[] filesToMerge)
{
var fiLines = File.ReadAllLines(fi.FullName).ToList();
fiLines.AddRange(filesToMerge.SelectMany(file => File.ReadAllLines(file)));
File.WriteAllLines(strOutputPath, fiLines.ToArray());
}
}
Usage
FileInfo fi = new FileInfo("input");
fi.MergeFiles("output", "File2", "File3");
I appreciate this question is almost old enough to (up)vote (itself), but for an extensible approach:
const string FileMergeDivider = "\n\n";
public void MergeFiles(string outputPath, params string[] inputPaths)
{
if (!inputPaths.Any())
throw new ArgumentException(nameof(inputPaths) + " required");
if (inputPaths.Any(string.IsNullOrWhiteSpace) || !inputPaths.All(File.Exists))
throw new ArgumentNullException(nameof(inputPaths), "contains invalid path(s)");
File.WriteAllText(outputPath, string.Join(FileMergeDivider, inputPaths.Select(File.ReadAllText)));
}