2013-05-28 4 views
0

Все,Транслейтинг C++ чтение файла/записи для чтения C# Файл/записи

Я делаю некоторые упражнения программирования на C++, а затем пытается перевести их на C# и других языках, чтобы освежить.

Этот пример исходит из главы. 11.2 из Нелл Дейл и Чипа Вейса «Программирование и решение проблем с помощью С ++» (пятое издание), с. 521-522. Это программа, которая принимает в этом файле (имя студента, ГПД, четыре класса, а класс курса) - давайте назовем его rec.in:

Mary Abbott 3,4 80 90 60 99 B

Боб Бейкер 4.0 90 90 90 95

Салли Картер 2.0 70 70 70 65 С

Билл Dansk 3.0 65 50 60 70 D

JoEllen Zureck 1,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#, но не работал на консоли. В результате, это немного ... беспорядочно ... работать над переводом. Я немного запутался в сопоставлении функции getline C++ в C#. Существует, конечно, 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 не назначена и используется как переключатель; это связано с тем, что он никогда не получает значение от ReadLine. Тем не менее, это академическое решение, если ReadLine действительно делит вещи.

ответ

3

Вы хотите использовать 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); 
} 

Методы я использую выше, не является абсолютно необходимым, например, вы могли бы гнездо StreamWriter использования внутри StreamReaders и сделать запись в пределах той же области. В версии C# вы перебираете содержимое файла по строкам. Каждый раз, когда мы получаем строку, мы хотим разбить ее на пробелы, чтобы получить ее субкомпоненты. Затем я добавляю класс оценки в список. Мы не хотим, чтобы новые строки в наших выходных строках, потому что WriteLine делает это автоматически. После того, как мы читаем файл, мы перебираем каждую строку в списке и записываем его в выходной файл.

+0

Эти выходные данные на консоли. Я ищу для вывода в файл. – nerdenator

+0

@AaronMcRuer да, я вижу это сейчас. Обновлено с соответствующей информацией. – evanmcdonnal

+0

Должен ли я каким-то образом пройти через поток? Я думаю, что я немного не понимаю, как он сравнивается с реализацией на C++. Реализация C++ - это поток, конечно, поэтому вещи разбиваются на куски, но реализация C# представляет собой функциональную реализацию. – nerdenator

1

Для проблемы с переключателем попробуйте это:

case GradeType.A: 
    outFile.Write("A\n"); 
    break; 

Вы работаете с перечислением и должен дать его на случай переключения.

Для других проблем, если вы хотите работать с каждой строкой в ​​файле, вы должны назначить ее строке, а затем обработать ее, чтобы извлечь необходимую информацию с помощью таких методов, как split и т. Д.

string line = inFile.ReadLine(); 
string[] data = line.Split(' '); 
record.stuName = string.Format("{0} {1}", data[0], data[1]); 
record.gpa = float.Parse(data[2]); 
.... 
+0

Это приводит меня к первой строке («Мэри») и не дальше. Остальная часть массива имеет нулевое значение ... как бы я прошел? Я думаю, вы должны быть очень близки к своей идее. – nerdenator

+0

Я думаю, что файл является записью более одной строки. В этом случае вам нужно использовать время чтения, как вам нужно. Не могли бы вы разместить содержимое переменной строки сразу после ее чтения. – stoyanov

Смежные вопросы