将C++文件读写转换为C#文件读写
本文关键字:文件读写 转换 C++ | 更新日期: 2023-09-27 18:15:42
全部,
我正在用C++做一些编程练习,然后尝试将它们翻译成C#和其他语言来复习。
这个例子来自Nell Dale和Chip Weems的"用C++编程和问题解决"(第五版(第11.2章,第521-522页。这是一个包含这个文件(学生姓名、平均成绩、四个成绩和课程成绩(的程序,我们称之为rec.in
:
Mary Abbott3.4 80 90 60 99 B
鲍勃·贝克4.0 90 90 90 95
萨莉·卡特2.0 70 70 70 65 C
Bill Dansk3.0 65 50 60 70天
JoEllen Zureck1.9 90 95 80 99
并且(或多或少(只是将其复制到另一个文件中。
以下是执行此操作的代码:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
const int MAX_STUDENTS = 150;
enum GradeType{A,B,C,D,F};
struct StudentRec
{
string stuName;
float gpa;
int examScore[4];
GradeType courseGrade;
};
StudentRec gradeBook[MAX_STUDENTS];
int main()
{
StudentRec record[MAX_STUDENTS];
ofstream outFile;
outFile.open("rec.out");
ifstream inFile;
inFile.open("rec.in");
for (int count = 0; count < MAX_STUDENTS; count++)
ReadValues(inFile, record[count]);
for (int count = 0; count <= MAX_STUDENTS; count++)
PrintValues(outFile, record[count]);
inFile.close();
outFile.close();
return 0;
}
void ReadValues(ifstream& inFile, StudentRec& record)
{
char letter;
char throwAway;
getline(inFile, record.stuName);
inFile >> record.gpa>>record.examScore[0]
>> record.examScore[1] >> record.examScore[2]
>> record.examScore[3] >> letter;
inFile.get(throwAway);
switch(letter)
{
case 'A' : record.courseGrade = A;
break;
case 'B' : record.courseGrade = B;
break;
case 'C' : record.courseGrade = C;
break;
case 'D' : record.courseGrade = D;
break;
case 'F' : record.courseGrade = F;
break;
}
}
void PrintValues(ofstream& outFile, StudentRec& record)
{
outFile << record.stuName << endl;
outFile << record.gpa << ' ' << record.examScore[0] << ' '
<< record.examScore[1] << ' '
<< record.examScore[2] << ' '
<< record.examScore[3] << ' ';
switch (record.courseGrade)
{
case A : outFile << 'A';
break;
case B : outFile << 'B';
break;
case C : outFile << 'C';
break;
case D : outFile << 'D';
break;
case F : outFile << 'F';
break;
}
outFile << endl;
}
我开始翻译成C#。我以前做过C#的工作,但没有做控制台的工作。因此,这有点。。。凌乱的翻译东西。我有点困惑于在C#中匹配C++的getline
函数。当然有System.IO.StreamReader
,但它每次只读取一行文件。如上所述,getline
以流格式执行。这会使用单词/字符之间的空格/换行符将其分解。使用C#的库选项,我将如何获得相同的结果?我并不完全接受System.IO.StreamReader
解决方案。
这是我的开始:
using System;
using System.IO;
namespace _112a
{
class Program
{
const int MAX_STUDENTS = 150;
enum GradeType{A,B,C,D,F};
struct StudentRec{
string stuName;
float gpa;
GradeType courseGrade;
};
StudentRec[] gradeBook = new StudentRec[MAX_STUDENTS];
static void Main(string[] args)
{
StudentRec[] record = new StudentRec[MAX_STUDENTS];
System.IO.StreamWriter outFile = new System.IO.StreamWriter("rec.out");
System.IO.StreamReader inFile = new System.IO.StreamReader("rec.in");
for (int count = 0; count < MAX_STUDENTS; count++)
{
ReadValues(inFile, record[count]);
}
for (int count = 0; count <= MAX_STUDENTS; count++)
{
PrintValues(outFile, record[count]);
}
inFile.Close();
outFile.Close();
}
static void ReadValues(StreamReader inFile, StudentRec record)
{
char letter;
char throwAway;
/*can't use getline, what do?*/
inFile.ReadLine();
switch (letter)
{
case 'A':
record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "A");
break;
case 'B':
record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "B");
break;
case 'C':
record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "C");
break;
case 'D':
record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "D");
break;
case 'F':
record.courseGrade = (GradeType)Enum.Parse(typeof(GradeType), "F");
break;
}
}
static void PrintValues(StreamWriter outFile, StudentRec record)
{
outFile.Write("{0}'n{1} {2} {3} ", record.stuName, record.examScore[0], record.examScore[1], record.examScore[2], record.examScore[3]);
switch(record.courseGrade)
{
case GradeType.A:
outFile.Write("A'n");
break;
case GradeType.B:
outFile.Write("B'n");
break;
case GradeType.C:
outFile.Write("C'n");
break;
case GradeType.D:
outFile.Write("D'n");
break;
case GradeType.F:
outFile.Write("F'n");
}
}
}
}
关于方法PrintValues
中的开关结构,我还有一个额外的问题:在每种情况下,C++文件中都指定它只接受record.courseGrade
字段,并将其与case
后面指定的参数进行比较。C#作为一种类型强的语言,不会让这种情况发生。。。如果将char
"A"与record.courseGrade
进行比较,则会得到类型不匹配错误。或者,不使用单引号(因此将其作为record.courseGrade
字段(会出现The name 'A' does not exist in the current context.
错误。我该如何最好地处理此问题?-已解决
我使用ReadLine((的困惑源于它的工作方式。在这种情况下,StudentRec
结构的多个成员被填充,但它们在结构中是独立的实体。我担心的是:
StudentRec.stuName = inFile.ReadLine();
并且具有用整行填充的StudentRec.stuName
,而在其它结构字段中没有任何内容。
此外,我们还存在letter
未分配并用作交换机的问题;这是由于它从未接收到来自CCD_ 17的值。然而,如果ReadLine
真的把事情分开了,这是一个学术性的解决方案。
您希望分别使用StreamReader和Writer。您可能要寻找的方法是ReadLine
和WriteLine
,StreamReader文档底部有一个适合您需求的工作示例。您只需要在while循环中更改文件路径和逻辑。文档可以在这里找到;
http://msdn.microsoft.com/en-us/library/system.io.streamreader.aspx
StreamWriter文档在这里,底部有一个同时使用读取器和写入器的示例;
http://msdn.microsoft.com/en-us/library/system.io.streamwriter.aspx
所有的方法都有逻辑名称,并且比它们的c++对应方法更容易实现。
我认为您的开关导致了编译错误,因为案例需要是case "A":
而不是case A:
。如果你把一个文字放在那里,它会进行字符串比较。它不理解A是什么,除非它是局部变量的名称。
EDIT:读取文件的样例代码;
// we need to alloc/init the streams inside for using blocks so they're properly disposed of
List<string> grades = new List<string>();
using (StreamReader inFile = new StreamReader("rec.in"))
{
string line;
while ((line = inFile.ReadLine()) != null)
{
string[] tokens = line.Split(' '); // split line on whitespace
if (tokens.Length > 7)
grades.Add(tokens[7]);
}
}
using (StreamWriter outFile = new StreamWriter("rec.out"))
{
foreach (string s in grades)
outFile.WriteLine(s);
}
我上面使用的技术并不是完全必要的,例如,您可以在StreamReaders中嵌套StreamWriter,并在同一范围内进行编写。在C#版本中,您逐行循环遍历文件的内容。每次我们得到一条线,我们都想把它分割在空间上,得到它的子组件。然后我将字母等级添加到列表中。我们不希望在输出字符串中出现换行符,因为WriteLine
会自动执行。读取文件后,我们循环遍历列表中的每个字符串,并将其写入输出文件。
对于开关的问题,请尝试以下操作:
case GradeType.A:
outFile.Write("A'n");
break;
您使用枚举,并且必须将其提供给开关情况。
对于其他问题,若您想处理文件中的每一行,您必须将其分配给一个字符串,然后通过拆分等方法对其进行处理以提取所需的信息
string line = inFile.ReadLine();
string[] data = line.Split(' ');
record.stuName = string.Format("{0} {1}", data[0], data[1]);
record.gpa = float.Parse(data[2]);
....