2014-10-16 4 views
0

Я чрезвычайно новичок в C++ (и вообще программирование), и я работаю над проектом, который меня озадачил (не трудно сделать ha). Проект включает файлы прямого доступа. Мы должны создать файл, состоящий из серии записей деталей. Вот некоторые из характеристик:Работа с файлами прямого доступа в C++

Должна содержать запись заголовка (заполнено 24 байта), указывающую количество действительных элементов .

Каждый (24 байт длиной) запись данных будет содержать инвентарный номер (4 цифры макс), описание (8 символов), счетчик (4 цифры), и индикатор «Тест часть» (4 цифры max => -1 - конец файла ).

Этот файл изначально будет содержать 20 незаполненных (фиктивных) записей и будет создан по порядку .

После того как файл был создан, будет доступен доступ к последовательному текстовому файлу на основе номеров акций, и в файл будут добавлены новые записей.

Когда обновление будет завершено, действительные записи о партиях будут напечатаны в порядке, начиная с запаса запись "1".

Обновление путем чтения файла обновления текста (prog4.dat) и ищет позицию файла, основанный на инвентарный номер (не забудьте запись в заголовка)

Например:

Initial (empty) 
Input (updates) 
    1 widgits 25 3 
    6 gidgits 12 8 
    8 kidgits 6 -1 
    3 didgits 11 6 
Output 
    1 widgits 25 
    3 didgits 11 
    6 gidgits 12 
    8 kidgits 6 

Я не знаю абсолютно ничего о файлах прямого доступа, поэтому рассматривал пару различных ссылок, которые я нашел в Google (http://cee-ux49.cee.illinois.edu/cee490/public_html/pdfs_vgs/aL23_Direct_Access_Files.pdf, и конкретно), но мне трудно понять, как сделать эту работу этой конкретной программы.

Я не очень много сделал для кода, поскольку, как я уже сказал, это меня озадачило, и то, что у меня есть, основано главным образом на этой первой ссылке, поэтому я не знаю, что это правильно (не уверен какой размер дать вектор, так как я не совсем уверен, что это было бы в моей конкретной проблеме (возможно, массив деталей?)), но вот что я мог бы придумать.

#include <iostream> 
#include <string> 
#include <fstream> 
#include <stream> 
using namespace std; 

class records { 
public: 
     int getStckNumber() { 
       return stockNumber; 
     } 
     void setStockNumber(int stockNum) { 
       stockNumber = stockNum; 
     } 

     string getItemDespcription() { 
       return itemDescription; 
     } 
     void setItemDespcription(string itemDescrip) { 
       itemDescription = itemDescrip; 
     } 

     int getItemAmount() { 
       return itemAmount; 
     } 
     void setItemAmount(int itemAmt) { 
       itemAmount = itemAmt; 
     } 

     int getNext() { 
       return next; 
     } 
     void setNext(int nxt) { 
       next = nxt; 
     } 
private: 
     int stockNumber; 
     string itemDescription; 
     int itemAmount; 
     int next; 
     int recNum; 
} 


int main() { 
     int stockNumber; 
     string itemDescription; 
     int itemAmount; 
     int next; 
     int recNum; 
     int recSize = sizeof(int) + sizeof(string) + sizeof(int) + sizeof(int) + sizeof(int); 

     istream updateFile; 
     updateFile.open("prog4.dat"); 
     if(!updateFile) { 
       cerr << "Open Failure" << endl; 
       exit(1); 
     } 
} 

Вот файл я буду использовать для обновлений:

10 zidgits 17 -1 
14 lidgits 2 7 
6 gidgits 12 8 
1 bidgits 25 3 
16 widgits 9 10 
7 midgits 0 2 
3 didgits 11 6 
5 tidgits 5 16 
2 pidgits 7 5 
8 kidgits 6 14 

Вот некоторые конкретные вопросы, которые у меня есть:

  1. Как бы идти о хранении информации от updateFile до переменных, которые будут записаны в выходной файл (еще не создан)?

  2. Как я могу получить данные в правильном порядке, поскольку он основан на последнем номере в каждой строке в файле updateFile.

Например, выходной файл должен начинаться с самой низкой stockNumber, который 1, поэтому на основе файла, элемент с stockNumber 1 является bidgits. Затем файл должен смотреть на последний номер в этой строке (3) и записывать информацию для элемента с этим количеством запаса (didgits) и так далее.

Это основные вопросы, которые возникают у меня прямо сейчас, но я уверен, что все это будет развиваться. Любая помощь была бы высоко оценена. Кроме того, это происходит примерно через 5 часов, поэтому я стараюсь придерживаться как можно большего кода, который у меня уже есть (я знаю, что гораздо больше добавится, конечно), если это вообще возможно.

+0

Я искал это, что может быть полезно: http://cee-ux49.cee.illinois.edu/cee490/public_html/pdfs_vgs/aL23_Direct_Access_Files.pdf По крайней мере, первые несколько страниц. – Galik

+0

Спасибо, это выглядит действительно полезно. –

+0

Мне просто сложно понять, как применить его к моей конкретной проблеме: -/ –

ответ

2

Что я хотел бы для такого проекта написать primitive функции для чтения и записи целых записей и обновления заголовка файла.

Я бы создал структуры типа POD для хранения отдельных записей, которые нужно читать или записывать в файлы данных.

Например:

struct header 
{ 
    uint32_t valid; // number of valid records 
    char pad[20]; // padding to make this object 24 bytes 
}; 

struct record 
{ 
    char no[4]; // stock number 
    char desc[8]; // description 
    uint32_t count; 
    uint32_t test_part; 
    char pad[4]; // padding to make this object 24 bytes 
}; 

Функция, чтобы написать заголовок (который всегда в позиции файла 0):

std::iostream& write(std::iostream& ios, const header& h) 
{ 
    ios.clear(); // clear any errors 
    ios.seekg(0); // move to beginning of file 
    ios.write(reinterpret_cast<const char*>(&h), sizeof(h)); // write the header to file 
    return ios; // return the stream (for easy error detection/chaining) 
} 

То же самое, чтобы написать запись при конкретное положение:

std::iostream& write(std::iostream& ios, const record& r, size_t pos) 
{ 
    ios.clear(); // clear any errors 
    ios.seekg(sizeof(header) + (sizeof(record) * pos)); // move to record's position 
    ios.write(reinterpret_cast<const char*>(&r), sizeof(r)); // write the record to file 
    return ios; // return the stream (for easy error detection/chaining) 
} 

Вы можете написать функцию инициализации в терминах этих примитивов:

std::iostream& init(std::iostream& ios, size_t num) 
{ 
    // Update the header to zero records 
    header h; 
    h.valid = 0; 
    write(ios, h); 

    // create each record with a -1 (EOF) marker 
    record r; 
    r.test_part = uint32_t(-1); 

    // output 20 copies of that record. 
    for(size_t pos = 0; pos < num; ++pos) 
     write(ios, r, pos); 

    return ios; 
} 

Тогда вызывающими все это на реальный файл немного, как этот:

int main() 
{ 
    assert(sizeof(header) == 24); 
    assert(sizeof(record) == 24); 

    // binary mode io! 
    std::fstream fs("records.dat", std::ios::in|std::ios::out|std::ios::binary); 

    if(!init(fs, 20)) 
    { 
     std::cerr << "ERROR: initializing data file:" << std::endl; 
     return 1; 
    } 

    // ... 
} 

ПРИМЕЧАНИЕ : Этот код поспешно написан и полностью непроверен и представлен просто как пример того, как к этой проблеме можно подойти. Надеюсь, это даст вам некоторые идеи.

ТАКЖЕ: Написание двоичных файлов, подобных этому, не очень переносимо между системами или даже между разными версиями одного и того же компилятора на одной платформе.

+0

Это замечательно! Быстрый вопрос, в основном, - это data.txt файл, который представляет собой тот, который я получаю от или будет ли это мой выходной файл? –

+0

@BethTanner Это файл, в котором хранятся записи. Не входной файл, я получаю это более подходящее имя. – Galik

+0

Хорошо спасибо, просто хотел быть уверенным.Так, где бы материал для входного файла переместился? –

2

Во-первых, у вас, кажется, есть 5 переменных-членов в вашем классе, хотя в каждом элементе есть только 4 данных. Это опасно.

После исправления этого я просто прочитал весь файл в вектор этих объектов. Для записи просто используйте небольшую петлю для перемещения по вектору в соответствии со следующим числом.

Вам не нужны все эти геттеры и сеттеры. Не обращайте внимания на то, что говорит Грэди Буч: вы единственный программист, и вы можете доверять себе, чтобы не испортить свои собственные данные. Даже если бы вы этого не сделали, вы могли бы легко связать его с сеттерами, так как напрямую обращались к переменной открытого участника.

Просто прочтите и проанализируйте файл с помощью cin, scanf или любого другого, что вы предпочитаете. Если все поля имеют фиксированную ширину, то чтение известного количества символов с помощью fread - это, вероятно, ваш самый простой вариант. Используйте atoi, чтобы делать числа из строк.

+0

Я думаю, что я могу обработать перенос их в вектор (возможно), но как бы я прокрутил его, используя число в конец? Я имею в виду, я понимаю концепцию цикла, а не как заставить ее перейти в нужное место на основе соответствующего номера. –

+0

Также, по переменным, я предполагаю, что это int recNum, от которого я должен избавиться, не так ли? –

+0

Речь идет о ** файлах прямого доступа **. Я думаю, это означает, что файлы не читаются последовательно, а доступны напрямую, используя функции 'seek' и' tell'. – Galik