difference between Metatrader CSV and C# StreamWriter CSV. How to solve it? - c#

I have a Code in Metatrader that writes some Quotes to CSV, but while doing same in C# the Expert advisor reads the values a different way....
This Code in MetaEditor writes the CSV file:
li_40 = FileOpen(ls_32, FILE_CSV|FILE_WRITE|FILE_SHARE_READ, ";");
if (li_40 > 0) {
FileWrite(li_40, ls_16);
FileClose(li_40);
This Writes in C#:
List<string> listB = new List<string>();
using (StreamReader reader = new StreamReader(File.OpenRead(oFile)))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
listB.Add(reader.ReadLine());
}
reader.Close();
}
using (StreamWriter swOut = new StreamWriter(oFile))
{
foreach (var item in listB)
{
swOut.Write(item);
swOut.Write(Environment.NewLine);
}
for (int i = 0; i <= gridIn.Columns.Count - 1; i++)
{
if (i > 0)
{
swOut.Write(", ");
}
value = dr.Cells[i].Value.ToString();
string vals = dr.Cells[2].Value.ToString();
int priceDecimalPlaces = vals.Split('.').Count() > 1
? vals.Split('.').ToList().ElementAt(1).Length
: 0;
string nell = "0";
if (priceDecimalPlaces == 3)
{
nell = "0.001";
}
if (priceDecimalPlaces == 5)
{
nell = "0.00001";
}
if (priceDecimalPlaces == 4)
{
nell = "0.0001";
}
//replace comma's with spaces
value = value.Replace(',', ' ');
//replace embedded newlines with spaces
value = value.Replace(Environment.NewLine, "");
If the difference between the C# double and the Metatrader's current double value is 0.12098-0.12096=2, the Metatrader won't see the value as 2 but something very much higher like 18,17 and so on, but writing this same value from the MetaTrader's code gives correct value...
I read the CSV using _lread:
uchar chBuff[1024];
int res = _lread(hFile, chBuff, 1);
//
//CreateFileA(
res = _lread(hFile, chBuff, 350);
ls_308 = CharArrayToString(chBuff, 0, res, CP_UTF8);
//Alert(Ls_84);
ls_308=StringSubstr(ls_308,0,StringFind(ls_308,"\r\n",0));
if (_lclose(hFile)<0) Print("Error closing");
I think there are some difference between C# doubles on Metatrader and normal Metatrader doubles

The error was caused by the System's encoding language which was different to UTF-8 that was specified in the Metatrader code
ls_308 = CharArrayToString(chBuff, 0, res, CP_UTF8);
So, I changed the UTF to All Code Page assigned by System by doing this
ls_308 = CharArrayToString(chBuff, 0, res, CP_ACP);
Hope someone find this useful..

Related

split a txt file into multiple files with the number of lines in each file being able to be set by a user

I'm writing something in C# and I need to find a way to split a text file into more files with the number of lines in the file being equivalent to a user input.
Example : file a had 1000 lines in it and I want the code to ask the user for a number and then use that number to make more files like this
a = 1000 lines .
Then after the code has run with the input of 300
a = 300 lines
b = 300 lines
c = 300 lines
d = 300 lines
e = 300 lines
Repeat that until the original file has been split into more files all with 300 lines .
This is what I have so far
var file = File.ReadAllLines(ofd.FileName);
Console.Write("> ");
int userlinestosplit = int.Parse(Console.ReadLine());
ArrayList fileA = new ArrayList();
for (int i = 0; i < userlinestosplit; i++)
{
string line = file[i];
fileA.Add(line);
}
int linesleft = file.Length - userlinestosplit;
ArrayList fileB = new ArrayList();
for (int i = linesleft; i < file.Length; i++)
{
string line = file[i];
fileB.Add(line);
}
string[] fileAArr = (string[])fileA.ToArray(typeof(string));
string[] fileBArr = (string[])fileB.ToArray(typeof(string));
string resdir = "results";
string modir = "splited";
Directory.CreateDirectory(resdir);
Directory.SetCurrentDirectory(resdir);
Directory.CreateDirectory(modir);
Directory.SetCurrentDirectory(modir);
File.WriteAllLines("FA.txt", fileAArr);
File.WriteAllLines("FB.txt", fileBArr);
Console.ReadKey();
Any help would be greatly appreciated
Here's a way to do it using streams. This has the benefit of not needing to read it all into memory at once, allowing it to work on very large files.
Console.Write("> ");
var maxLines = int.Parse(Console.ReadLine());
var filename = ofd.FileName;
var fileStream = File.OpenRead(filename);
var readStream = new StreamReader(fileStream);
var nameBase = filename[0..^4]; //strip .txt
var parts = 1;
var notfinished = true;
while (notfinished)
{
var part = File.OpenWrite($"{nameBase}-{parts}.txt");
var writer = new StreamWriter(part);
for (int i = 0; i < maxLines; i++)
{
writer.WriteLine(readStream.ReadLine());
if (readStream.EndOfStream)
{
notfinished = false;
break;
}
}
writer.Close();
parts++;
}
Console.WriteLine($"Done splitting the file into {parts} parts.");
Splitting text file to multiple parts
public void SplitFile(string inputFile, int size, string path)
{
int index = 0;
string s = string.Empty;
using (StreamReader sr = File.OpenText(inputFile))
{
while (true)
{
if (sr.EndOfStream) break;
using (StreamWriter output = new StreamWriter($"{path}\\part{index}.txt", false, Encoding.UTF8))
{
int linesRead = 0;
while ((s = sr.ReadLine()) != null && linesRead < size)
{
output.WriteLine(s);
linesRead++;
}
}
index++;
}
}
}
How to use:
var inputFile = "test.txt";
int size =300;
SplitFile(inputFile, size, "c:\\data");

New line after foreach loop

This code works as it should
foreach (char c in partToDecode)
{
var sum = c - 48;
if (sum > 40)
{
sum = sum - 8;
}
string suma = Convert.ToString(sum, 2).PadLeft(6, '0');
File.AppendAllText(#"C:\Users\jakub\Pulpit\binary.txt", suma);
}
We're inside invisible for i loop (i meant that foreach and this newline is inside of for loop named I) so I need a new line in for loop after foreach loop.
This code isn't working as i wish to, i've got a new line at the beginning and in 2nd line a plain text, the desire is to have a new line after each finish of the foreach loop
string sumaaa = Convert.ToString(sum, 2).PadLeft(6, '0');
File.AppendAllText(#"C:\Users\jakub\Pulpit\binary.txt", sumaaa);
}
FileStream stream = new FileStream(#"C:\Users\jakub\Pulpit\binary.txt", FileMode.Open);
StreamWriter sw = new StreamWriter(stream);
sw.Write("\n");
sw.Close();
}
This is kinda small, after that I have a code for splitting bits to convert small pieces of it to decimal. It worked earlier but i inserted it inside a comment and now it writes nothing. This loop stands alone after all, runs after clicking ok, then i have a form2 which is displayed always, no errors.
for (var k = 0; k < binlines.Count(); k++)
{
var binline = binlines[k];
if (binline != null) //in case it was an empty line error (it's not)
{
string partmessage = binline.Substring(0, 6);
string partdecoded = Convert.ToInt32(partmessage, 2).ToString();
string partmessage2 = binline.Substring(6, 2);
string partdecoded2 = Convert.ToInt32(partmessage2, 2).ToString();
string partmessage3 = binline.Substring(8, 30);
string partdecoded3 = Convert.ToInt32(partmessage3, 2).ToString();
string so on to 15
File.AppendAllText(#"C:\Users\jakub\Pulpit\decimal.txt", partdecoded + "," + partdecoded2 + "," partdecoded3 + "," + partdecoded4...)
}
else
{
}
Now i've got an exception of out of range "index and length must reference to location in string"
I suggest not using a csv format to start with, and write your native binary data to disk. In that case you could just use BinaryReader and BinaryWriter that makes this trivial.
Also it probably worth making some healper methods or a class that can take care of the reading of binary data to int.
Given
public struct BinReader
{
private readonly string _line;
private int _index;
public BinReader(string line)
{
_line = line;
_index = 0;
}
public int GetInt(int length)
{
var result = Convert.ToInt32(_line.Substring(_index, length), 2);
_index += length;
return result;
}
}
Usage
// some test data
var binLines = new List<string>()
{
Convert.ToString(1, 2) + Convert.ToString(2, 2) + Convert.ToString(3, 2) + Convert.ToString(4, 2) + Convert.ToString(5, 2),
Convert.ToString(1, 2) + Convert.ToString(2, 2) + Convert.ToString(3, 2) + Convert.ToString(4, 2) + Convert.ToString(5, 2),
};
// write to file
using (var sw = new BinaryWriter(new FileStream("SomeFileName.dat", FileMode.Create, FileAccess.ReadWrite)))
{
foreach (var reader in binLines.Select(line => new BinReader(line)))
{
sw.Write(reader.GetInt(1));
sw.Write(reader.GetInt(2));
sw.Write(reader.GetInt(2));
sw.Write(reader.GetInt(3));
sw.Write(reader.GetInt(3));
}
}
// read from file
using (var br = new BinaryReader(new FileStream("SomeFileName.dat", FileMode.Open, FileAccess.ReadWrite)))
{
foreach (var reader in binLines.Select(line => new BinReader(line)))
{
Console.WriteLine(br.ReadInt32());
Console.WriteLine(br.ReadInt32());
Console.WriteLine(br.ReadInt32());
Console.WriteLine(br.ReadInt32());
Console.WriteLine(br.ReadInt32());
}
}
Proof it works
1
2
3
4
5
1
2
3
4
5

Reading lines from a text file, converting them, then writing back to new file

I have some basic knowledge of C#, but I am having trouble coding something that seems simple in concept. I want to read a file (.asm) containing values such as
#1
#12
#96
#2
#46
etc.
on multiple consecutive lines. I then want to get rid of the # symbols (if they are present), convert the remaining number values to binary, then write these binary values back to a new file (.hack) on their own lines. There isn't a set limit on the number of lines, which is my biggest issue as I don't know how to check for lines dynamically. So far I can only read and convert lines if I code to look for them, then I can't figure out how to write these values on their own lines in the new file. Sorry if this sounds a bit convoluted, but any help would be appreciated. Thanks!
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
var line = File.ReadAllText(openFileDialog1.FileName);
using (StreamWriter sw = File.CreateText("testCode.hack"))
{
var str = line;
var charsToRemove = new string[] {"#"};
foreach (var c in charsToRemove)
{
str = str.Replace(c, string.Empty);
}
int value = Convert.ToInt32(str);
string value2 = Convert.ToString(value, 2);
if (value2.Length < 16)
{
int zeroes = 16 - value2.Length;
if(zeroes == 12)
{
sw.WriteLine("000000000000" + value2);
}
}
else
{
sw.WriteLine(value2);
}
}
This code should help you get going real fast:
static void Main(string[] args)
{
string line = string.Empty;
System.IO.StreamReader reader = new System.IO.StreamReader(#"C:\test.txt");
System.IO.StreamWriter writer = new System.IO.StreamWriter(#"C:\test.hack");
while ((line = reader.ReadLine()) != null) // Read until there is nothing more to read
{
if (line.StartsWith("#"))
{
line = line.Remove(0, 1); // Remove '#'
}
int value = -1;
if (Int32.TryParse(line, out value)) // Check if the rest string is an integer
{
// Convert the rest string to its binary representation and write it to the file
writer.WriteLine(intToBinary(value));
}
else
{
// Couldn't convert the string to an integer..
}
}
reader.Close();
writer.Close();
Console.WriteLine("Done!");
Console.Read();
}
//http://www.dotnetperls.com/binary-representation
static string intToBinary(int n)
{
char[] b = new char[32];
int pos = 31;
int i = 0;
while (i < 32)
{
if ((n & (1 << i)) != 0)
{
b[pos] = '1';
}
else
{
b[pos] = '0';
}
pos--;
i++;
}
return new string(b);
}
My suggestion create a List<string>. Here are steps
Read input (.asm) file into List
Open StreamWriter for output (.hack) file.
Loop through List<string> modify the string and write into file.
Code Example:
List<string> lstInput = new List<string>();
using (StreamReader reader = new StreamReader(#"input.asm"))
{
string sLine = string.Empty;
//read one line at a time
while ((sLine = reader.ReadLine()) != null)
{
lstInput.Add(sLine);
}
}
using (StreamWriter writer = new StreamWriter(#"output.hack"))
{
foreach(string sFullLine in lstInput)
{
string sNumber = sFullLine;
//remove leading # sign
if(sFullLine.StartsWith("#"))
sNumber = sFullLine.Substring(1);
int iNumber;
if(int.TryParse(sNumber, out iNumber))
{
writer.WriteLine(IntToBinaryString(iNumber));
}
}
}
public string IntToBinaryString(int number)
{
const int mask = 1;
var binary = string.Empty;
while(number > 0)
{
// Logical AND the number and prepend it to the result string
binary = (number & 1) + binary;
number = number >> 1;
}
return binary;
}
Reference: IntToBinaryString method.
NOTE: Int to Binary String method mentioned in the answer of #TheDutchMan is better choice.

C# Check EOF in text file to fix array

I have a code to read text file and save the data into a double array to plot graph:
string filename = openFileDialog1.FileName;
var lineCount = 0;
using (var reader = File.OpenText(#filename))
{
string line;
while ((line = reader.ReadLine()) != null)
{
var data = line.Split(',');
GlobalDataClass.dDataArray[lineCount, 0] = double.Parse(data[0]);
GlobalDataClass.dDataArray[lineCount, 1] = double.Parse(data[1]);
lineCount++;
}
ShowGraphData(lineCount);
}
And I have created a public class that initiate the array to [2000,2]:
static class GlobalDataClass
{
public static double[,] dDataArray = new double[2000, 2];
public static long iTotalReadingPoint;
}
My text file will be like:
0,29
1,31
2,32
3,32
4,30
However I want my program to detect the EOF so that the text file can contain random rows and still able to plot the graph not restricted to 2000 rows. Is it possible?please advice.TQ
If you want to use same class then try given code. This is not most optimum memory usage wise but still this should work.
string filename = openFileDialog1.FileName;
var lineCount = 0;
while ((line = reader.ReadLine()) != null)
{
if (GlobalDataClass.dDataArray.GetLength(0) == lineCount)
{
double[,] newTemp = GlobalDataClass.dDataArray;
int increaseLenght = newTemp.Length + 1000;
GlobalDataClass.dDataArray = new double[increaseLenght, 2];
Array.Copy(newTemp, GlobalDataClass.dDataArray, newTemp.LongLength);
}
var data = line.Split(',');
GlobalDataClass.dDataArray[lineCount, 0] = double.Parse(data[0]);
GlobalDataClass.dDataArray[lineCount, 1] = double.Parse(data[1]);
lineCount++;
}
The StreamReader class has a boolean property named EndOfStream that is essentially EoF for FileStream objects, and there's the Peek() method which is usually the standard way of reading until EoF.
var reader = File.OpenText( ... );
while( reader.Peek() != -1 ) //Peek() returns -1 on EoF or if the stream is not seekable.
{
var line = reader.ReadLine();
...
}
However reading from the file isn't really the problem if you don't want to be restricted to 2,000 lines. You might consider using a generic container of some flavour. For example:
using System.Collections.Generic;
string line = "12,34";
var dDataList = new List<KeyValuePair<double, double>>();
string[] parts = line.Split( ',' );
dDataList.Add( new KeyValuePair<double, double>( Double.Parse( parts[0] ), Double.Parse( parts[1] ) ) );
...
foreach( var pair in dDataList )
Console.WriteLine( "{0} => {1}", pair.Key, pair.Value ); // 12 => 34
Will let you add as many pairs of doubles as you want, within reason, without having to fiddle with array resizing/copying or any of that nasty business. It's generally considered good practice to use a container like List<T> when dealing with an unknown amount of data, and to use arrays when you know exactly how much data you're going to have or the absolute maximum amount of data you can have.
I think you're asking your question a bit wrong; The problem you have is that you are declaring an array of 2000 unit fixed length, but you actually want it to be dynamic length. As Abhinav said, a list may work for you:
firstly, you might consider creating a class/struct for your coordinates:
public class Coordinate
{
public double x;
public double y;
}
Then, create a list of coordinates (of 0 length initially)...
static class GlobalDataClass
{
public static List<Coordinate> dDataArray = new List<Coordinate>();
public static long iTotalReadingPoint;
}
And then add Coordinate objects to your list as you find new lines..
string filename = openFileDialog1.FileName;
var lineCount = 0;
using (var reader = File.OpenText(#filename))
{
string line;
while ((line = reader.ReadLine()) != null)
{
var data = line.Split(',');
Coordinate coord = new Coordinate();
coord.x = double.Parse(data[0]);
coord.y = double.Parse(data[1]);
GlobalDataClass.dDataArray.Add(coord);
lineCount++;
}
ShowGraphData(lineCount);
}

The process cannot access the file because it is being used (error)

I'm trying to move line in a text file up by one then rewrite it back to the original file, but getting error for some reason, can't seem to figure it out.
using (StreamReader reader = new StreamReader("file.txt"))
{
string line;
int Counter = 0;
while ((line = reader.ReadLine()) != null)
{
string filepath = "file.txt";
int i = 5;
string[] lines = File.ReadAllLines(filepath);
if (lines.Length >= i)
{
string tmp = lines[i];
lines[i] = lines[i-1];
lines[i-1] = tmp;
File.WriteAllLines(filepath, lines);
}
}
Counter++;
}
You are opening the file to read in this line:
using (StreamReader reader = new StreamReader("file.txt"))
At this point it is open and being used.
You then, later on have:
string[] lines = File.ReadAllLines(filepath);
Trying to read from the same file.
It is not clear what you are trying to achieve, but this will not work.
From what I can see, you don't need the reader at all.
I assume that you actually want to swap each line(?) in the file, because of this code snippet:
string tmp = lines[i];
lines[i] = lines[i-1];
lines[i-1] = tmp;
So here's an approach that should work:
String[] lines = System.IO.File.ReadAllLines(path);
List<String> result = new List<String>();
for (int l = 0; l < lines.Length; l++)
{
String thisLine = lines[l];
String nextLine = lines.Length > l+1 ? lines[l + 1] : null;
if (nextLine == null)
{
result.Add(thisLine);
}
else
{
result.Add(nextLine);
result.Add(thisLine);
l++;
}
}
System.IO.File.WriteAllLines(path, result);
Edit: Here's the slightly modified version that swaps only one line with it's previous line, since you've commented that this is your requirement:
String[] lines = System.IO.File.ReadAllLines(path);
List<String> result = new List<String>();
int swapIndex = 5;
if (swapIndex < lines.Length && swapIndex > 0)
{
for (int l = 0; l < lines.Length; l++)
{
String thisLine = lines[l];
if (swapIndex == l + 1) // next line must be swapped with this
{
String nextLine = lines[l + 1];
result.Add(nextLine);
result.Add(thisLine);
l++;
}
else
{
result.Add(thisLine);
}
}
}
System.IO.File.WriteAllLines(path, result);
Where you are trying to open the file to write it is inside a method thats already using a streamreader to open it, stream reader opens it, file writer tries to open it but cant because it is already open,
do not read and write a file at the same time
1.if the file is small, just load it, change it, and write back.
2.if the file is huge, just open another temp file for output,
the remove/delete the first file, and then rename the second file.
Instead of having:
using (StreamReader reader = new StreamReader("file.txt"))
{
...
string[] lines = File.ReadAllLines(filepath);
}
Use:
using (StreamReader reader = new StreamReader("file.txt"))
{
string line;
string[] lines = new string[20]; // 20 is the amount of lines
int counter = 0;
while((line=reader.ReadLine())!=null)
{
lines[counter] = line;
counter++;
}
}
This will read all the lines from the file and put them into 'lines'.
You can do the same with the Writing part of the code, but this way reads from the file using only 1 process. It will read all the lines then dispose and close itself.
Hope this Helps!

Categories

Resources