Why is StreamWriter writing crosses and Chinese characters? - c#

I have a little script that converts a pixel art image into a string, using 'X' for opaque pixels, ' ' for transparent pixels, and '\n' after each row. I want to then write this string to a text file, which seems simple enough.
[SerializeField] Sprite sprite;
[SerializeField] string newFileName;
private string textFilesFolderLocation = //A location on my computer.
private string fileExtension = ".txt";
public void CreateTextDocument() {
string ascii = CreateAscii();
string path = textFilesFolderLocation + #"\" + newFileName + fileExtension;
if (File.Exists(path)) {
File.Delete(path);
}
using (StreamWriter streamWriter = new StreamWriter(path)) {
streamWriter.Write(ascii);
}
}
private string CreateAscii() {
StringBuilder stringBuilder = new StringBuilder();
Texture2D pixels = sprite.texture;
for (int y = pixels.height - 1; y >= 0; y--) {
for (int x = 0; x < pixels.width; x++) {
Color pixel = pixels.GetPixel(x, y);
if (pixel.a > 0) {
stringBuilder.Append("x");
}
else {
stringBuilder.Append(" ");
}
}
stringBuilder.Append('\n');
}
return stringBuilder.ToString();
}
This works as expected with ~90% of my images, but a few are writing some seemingly bizarre characters to their text files! Variations of the following:
"...††††††††††††††††††††††††††††††††††††††††††††††††††
††††††††††††††††††††††††††††††††††††††††††††††††砠†
⁸††††††††砠†硸††††††††††††††††††††††††††††††砠†††††
††††砠†††††砠砠††††††††††††††††††††††††††††⁸††††††††
††††††††††††..." (the full text is around 50,000 characters long)
After investigating, I can confirm that CreateAscii() is working correctly. Printing the string to the console reveals that it is comprised of 'x' and ' ', as expected.
I have found that attempting to write simple messages like "Hello World" works as expected, and that writing a small piece of the ascii string also works. But with the few problematic images, trying to write the whole string results in "...†砠†硸†††...".
Even if I try to write small pieces sequentially like
for (int i = 0; i < ascii.Length; i++) {
using (StreamWriter streamWriter = new StreamWriter(path, append: true)) {
streamWriter.Write(ascii[i]);
}
}
I still get exclusively "...†砠†硸†††..." in my text file.
Does anybody know what might be going on?

Thanks to the helpful replies in the comments, I learned that Notepad was having trouble displaying my files correctly. Opening the .txt files with a different viewer enabled me to see the text properly.
I still don't know what the root problem was, but this is good enough for me!

Related

Incrementing a filename if the file already exists VB.NET to C# conversion

I am currently rewriting some software i created from VB.NET to C# due to additional image analysis functions and filters that are not possible in VB.NET. Part of the program automatically creates a new folder for the day if one does not already exist (that works fine) and it is then supposed to start saving images stored in the image buffer of the camera to file while incrementing the file name. I am not entirely sure if i am using the correct method here as i am trying to convert from VB.NET.
private void tmAutoCap_Tick(object sender, EventArgs e)
{
if (dAltitudeAngle < Convert.ToDouble(tbSolarAltSet.Text) & cbDarkSubAC.Checked == true)
{
try
{
ImageBuffer ImgBuffer = default(ImageBuffer);
int x = 0;
int y = 0;
int BytesPerLine = 0;
Cursor = Cursors.WaitCursor;
int i = 0;
string FileMask = (Global_Variables.NewDirectory + "\\AutoCap_{0}.bmp");
string Filename = "";
Filename = string.Format(FileMask, i);
while (System.IO.File.Exists(Filename))
{
i += 1;
Filename = string.Format(FileMask, i);
}
Bitmap Dark = Image.FromFile(tbDarkRoot.Text, true) as Bitmap;
ImgBuffer = IcImagingControl1.ImageBuffers[1];
// Calculate the count of bytes ber line using the color format and the
// pixels per line of the image buffer.
BytesPerLine = (ImgBuffer.BitsPerPixel / 8) * ImgBuffer.PixelPerLine - 1;
for (y = 0; y <= ImgBuffer.Lines - 1; y++)
{
for (x = 0; x <= BytesPerLine; x++)
{
if (Dark.GetPixel(x, y).R <= ImgBuffer[x, y])
{
ImgBuffer[x, y] = Convert.ToByte(ImgBuffer[x, y] - Dark.GetPixel(x, y).R);
}
else
{
ImgBuffer[x, y] = 0;
}
}
}
ImgBuffer.SaveAsBitmap(Filename);
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace);
System.IO.File.AppendAllText(Application.UserAppDataPath + "\\SkyCamErrorLog.txt", string.Format("{0}{1}{2}{3}", Environment.NewLine, DateTime.Now.ToString(), Environment.NewLine, ex.ToString()));
}
I had expected this to look for files and if it found any then automatically increment from the highest file already there by use of the filemask but it always fails to create any file and the error message thrown out is:
TIS.Imaging.ICException: Unknown error occurred Base Library Error : Permission denied
at TIS.Imaging.ImageBuffer.SaveImage(String filename)
at TIS.Imaging.ImageBuffer.SaveAsBitmap(String filename)
at Sky_Cam_Version_2.SkyCamForm.tmAutoCap_Tick(Object sender, EventArgs e)
For this reason i believe there is something wrong with the way i am trying to create the filename.
So the issue was not so much in the code here as it was actually doing the right thing. The issue was elsewhere in the code where i defined "NewDirectory" i had the code simply as
var NewDirectory = (tbSaveFilesLocation.Text + "\\" + NewFolder);
What i should have had is what i have now which actually defines the global variable so i can call it from elsewhere.
Global_Variables.NewDirectory = (tbSaveFilesLocation.Text + "\\" + NewFolder);
It is set as a global variable as the directory is created based on a timer. When the timer ticks it looks to see if a directory exists with the current date/time and if it does not it creates a new folder and this then becomes the folder that all new images should be saved to.
The debugger was showing me the answer i just couldn't see it for looking as i was so focused on the output of "\AutoCap_{0}.bmp" which returned a correct result i forgot that it should have had the results of Global_Variables.NewDirectory in front of it therefor it was trying to write a file with the correct name but without any directory referenced.

wrong format when saving to file

I am trying to save a String Builder to a file but it doesn't make new line.
the output should look like
output without new line
class Program
{
static public void justify(List<string> words, int width)
{
//some code to build the arrays
int ii = 0, jj;
StringBuilder builder = new StringBuilder();
do
{
jj = result[ii];
for(int k = ii; k < jj; k++)
{
builder.Append(words[k] + " ");
}
builder.Append("\n");
ii = jj;
}
while(jj < words.Count);
Console.WriteLine(builder.ToString());
StreamWriter file = new StreamWriter("output.txt");
file.Write(builder.ToString());
file.Close();
}
static void Main(string[] args)
{
string file_extention, file1;
file1 = Console.ReadLine();
file_extention = "C:\\Users\\sayed\\Desktop\\" + file1 + ".txt";
string text = System.IO.File.ReadAllText(#file_extention);
result = text.Split(' ').ToList();
justify(result, 10);
}
}
That's because the you should use \r\n for new lines in Windows. \n is Unix. You should use
builder.AppendLine();
which does this automatically. More precisely, AppendLine() appends a \r\n on non-Unix platforms and a string \n on Unix platforms.
Note that your file does indeed contain the \n which some editors do interpret as line breaks even on Windows. Notepad, for instance, does not.
Replace
builder.Append("\n");
with
builder.Append(Environment.NewLine);
Then open your file with notepad++ instead of window's default text editor.
I believe your \n characters are being ignored by notepad and so they aren't rendering. On Windows machines, it expects a \r\n to render a newline and Environment.NewLine will make sure you get the right one.

Large File - Adding Lines - Out Of Memory

I have a very large sql insert file which is throwing "out of memory" errors when running it in SQL Enterprise Manager.
The advice I have seen is to add the "GO" command every X amount of rows to the inserts are "batched".
I am trying to write a small function to read the file and every 50 lines add a row with the text "GO"
The code I have written is also throwing System.OutOfMemoryException when I run it.
Can anyone suggest a better way of writing my code to fix this problem please?
This is what I have written:
public static void AddGo()
{
int currentline = 0;
string FilePath = #"C:\Users\trevo_000\Desktop\fmm89386.sql";
var text = new StringBuilder();
foreach (string s in File.ReadAllLines(FilePath))
{
// add the current line
text.AppendLine(s);
// increase the line counter
currentline += 1;
if (currentline == 50)
{
text.AppendLine("GO");
currentline = 0;
}
}
using (var file = new StreamWriter(File.Create(#"C:\Users\trevo_000\Desktop\fmm89386Clean.sql")))
{
file.Write(text.ToString());
}
}
You're keeping the file in memory and then writing it from memory to a file. Instead of doing that write the output file as you work through the input file; this sort of thing:
public static void AddGo() {
int currentline = 0;
string inputFilePath = #"C:\Users\trevo_000\Desktop\fmm89386.sql";
string outputFilePath = #"C:\Users\trevo_000\Desktop\fmm89386Clean.sql";
using (var outputFileStream=File.CreateText(outputFilePath)) {
foreach (string s in File.ReadLines(inputFilePath))
{
// add the current line
outputFileStream.WriteLine(s);
// increase the line counter
currentline += 1;
if (currentline == 50)
{
outputFileStream.WriteLine("GO");
currentline = 0;
}
}
}
}
Note the use of ReadLines on the input file, rather than ReadAllLines - see What is the difference between File.ReadLines() and File.ReadAllLines()? for more info on that.

Get number of lines in file and add first 40 characters

As part of an assignment -
The User selects a file extension (.txt, .bat, or .xyz)
A list of files from a folder with that extension is shown
The user then selects a file from the list and are shown the first 40 characters of each of its first four lines (or as many lines as present if less than four lines are recorded in the file). If there are more lines left in the file, output a string: “xx more lines are not shown.” (substitute xx with the correct number).
I can't seem to wrap my head around number 3. Any help or pointers are greatly appreciated.
namespace unit9Assignment
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//add the extensions to the c box.
comboBox1.Items.Add(".txt");
comboBox1.Items.Add(".xyz");
comboBox1.Items.Add(".bat");
//make .txt the default selection
comboBox1.SelectedItem = ".txt";
tabControl1.SelectedIndexChanged += tabControl1_SelectedIndexChanged;
}
/******Tab Click Event********/
private void tabControl1_SelectedIndexChanged(Object sender, EventArgs e)
{
switch ((sender as TabControl).SelectedIndex)
{
case 0:
break;
case 1:
fileName(comboBox1.Text);
break;
case 2:
fileContent(Files.SelectedItem.ToString());
break;
}
}
/******Get Files Based on Selection*******/
public void fileName(string fileExt)
{
List<string> listOfFiles = new List<string>();
string[] fileExtArray = Directory.GetFiles(#"C:\Users\Public", "*" + fileExt);
foreach (string fileExtFile in fileExtArray)
{
listOfFiles.Add(fileExtFile);
}
Files.DataSource = listOfFiles;
}
/******Display 4 Lines # 40 Characters Per Line*********/
public void fileContent(string fileName)
{
int numberOfLines = File.ReadLines(#fileName).Count(),
remainingLines = numberOfLines - 4;
//THIS PRINTS OUT 4 LINES # 40 CHARACTERS PER LINE IF A FILE HAS LESS THAN 5 LINES
if (numberOfLines < 5)
{
foreach (string line in File.ReadLines(fileName))
{
richTextBox1.AppendText(line.Substring(0, 40) + Environment.NewLine);
Console.WriteLine(line.Substring(0, 40));
}
}
// NO CLUE WHAT TO DO
else
{
}
}
}
}
Rather than checking the number of lines in the file, why don't you just go ahead and start printing, and stop after 4 lines? Something like this:
StreamReader fileIn = new StreamReader(fileName);
for(int i=0; i<4 && !fileIn.EndOfStream; ++i)
{
string line = fileIn.ReadLine();
if(line.Length > 40)
richTextBox1.AppendText(line.Substring(0,40) + Environment.NewLine);
else
richTextBox1.AppendText(line + Environment.NewLine);
}
int j;
for(j=0; !fileIn.EndOfStream; ++j)
fileIn.ReadLine();
if(j>0)
richTextBox1.AppendText(j.ToString() + " more lines are not shown.";
fileIn.Close();
... To clarify, this would be your entire fileContent method. You actually do not need to know the number of lines in the file. Of course, this method won't work if you have more lines in your file than an int variable can hold, but I assume you're not working with such long files.
How about this:
public void fileContent(string fileName)
{
var lines = File.ReadLines(#fileName);
foreach (string line in lines.Take(4))
{
richTextBox1.AppendText(line.Substring(0, 40) + Environment.NewLine);
}
var remaining = lines.Count() - 4;
if (remaining > 0)
richTextBox1.AppendText(remaining + " more line(s) are not shown.");
}
The Take() documentation is here.
Giving answers to homework is bad practice. Instead here are some pointers to help you wrap your head around your problem:
//read a file
var lines = File.ReadLines("myfile");
//get the first 4 lines of your file
var first4 = lines.Take(4);
//get the first 40 characters of the first line of your file
var first40Chars = lines.FirstOrDefault().Take(40);
//get the remaining number of lines
var remainingCount = lines.Count() - 4;
Pulling up a dialog to show files is quite easy also. The WinForms FileDialog can help you there.

reading and writing multiple files at the same time and performing same tasks on them

I am a beginner to programming. I wrote a code in C# to open a single file (that has 4 columns of data) and extract the fourth column into a list. Then did some basic work on the data to extract the mean, minimum and maximum values of the data set. Then, the results was written to dedicated files for the mean, minimum and maximum values.
Now I want to repeat the same tests but for a multiple sets of files - each with over 100,000 lines of data. I want to enable the program to read a multiple set of files in the same folder and then do the same calculations for each file and compile all the results for mean, minimum and maximum values into separate folders, as before.
The code for the single file is as follows;
private void button1_Click_1(object sender, EventArgs e)
{
string text = "";
DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
// create a list to insert the data into
List<float> noise = new List<float>();
int count = 0;
float sum = 0;
float mean = 0;
float max = 0;
float min = 100;
TextWriter tw = new StreamWriter("c:/Users/a3708906/Documents/Filereader - 13062012/Filereader/date.txt");
if (result == DialogResult.OK) // Test result.
{
string file = openFileDialog1.FileName;
FileInfo src = new FileInfo(file);
TextReader reader = src.OpenText();
text = reader.ReadLine();
// while the text being read in from reader.Readline() is not null
while (text != null)
{
text = reader.ReadLine();
if (text != null)
{
string[] words = text.Split(',');
noise.Add(Convert.ToSingle(words[3]));
// write text to a file
tw.WriteLine(text);
//foreach (string word in words)
//{
// tw.WriteLine(word);
//}
}
}
}
tw.Close();
TextWriter tw1 = new StreamWriter("c:/Users/a3708906/Documents/Filereader - 13062012/Filereader/noise.txt");
foreach (float ns in noise)
{
tw1.WriteLine(Convert.ToString(ns));
count++;
sum += ns;
mean = sum/count;
float min1 = 0;
if (ns > max)
max = ns;
else if (ns < max)
min1 = ns;
if (min1 < min && min1 >0)
min = min1;
else
min = min;
}
tw1.Close();
TextWriter tw2 = new StreamWriter("c:/Users/a3708906/Documents/Filereader - 13062012/Filereader/summarymeans.txt");
tw2.WriteLine("Mean Noise");
tw2.WriteLine("==========");
tw2.WriteLine("mote_noise 2: {0}", Convert.ToString(mean));
tw2.Close();
TextWriter tw3 = new StreamWriter("c:/Users/a3708906/Documents/Filereader - 13062012/Filereader/summarymaximums.txt");
tw3.WriteLine("Maximum Noise");
tw3.WriteLine("=============");
tw3.WriteLine("mote_noise 2: {0}", Convert.ToString(max));
tw3.Close();
TextWriter tw4 = new StreamWriter("c:/Users/a3708906/Documents/Filereader - 13062012/Filereader/summaryminimums.txt");
tw4.WriteLine("Minimum Noise");
tw4.WriteLine("=============");
tw4.WriteLine("mote_noise 2: {0}", Convert.ToString(min));
tw4.Close();
}
I will be grateful if someone could help to translate this code for working with multiple files. Thank you.
Wrap your logic for processing a single file into a single Action or a void-returning function, then enumerate the files, switch them to ParallelEnumerable and call Parallel.ForAll
For example, if you made an Action or function named DoStuff(string filename) which will do the process for a single file, you can then call it with :
Directory.EnumerateFiles(dialog.SelectedPath).AsParallel().ForAll(doStuff);
Your current code will work if you simply use Directory.GetFiles() properly. The easiest way to do it would be to have three inputs; one to get the Directory, and a second to get the file extension (if wanted), and a checkbox to ask whether or not you want to recursively search the folders or not.
Then instead of
string file = openFileDialog1.FileName;
you would instead have something like
//ensure the default fileExtensionDropdown.SelectedValue is "*"
string[] filePaths;
if(chkRecursiveSearch.IsChecked == true)
filePaths = Directory.GetFiles(dlgFolderBrowser.SelectedPath, #"*"+ddlFileExtension.SelectedValue, SearchOption.AllDirectories);
else
filePaths = Directory.GetFiles(dlgFolderBrowser.SelectedPath, #"*"+ddlFileExtension.SelectedValue);
Then you can use:
for(string path in filePaths){ // do things }
to handle each file path the way you are right now.
Please note the code I've put here is definitely not as idiomatic and tidy as it could be, but since you said you were a beginner I decided to be a bit more clear. If requested I'll put up a more idiomatic take on things, though if we do that we should probably clean up your initial code a bit as well.

Categories