Работа с файлами прямого доступа в переполнении стека

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

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

Каждая (24 байта) запись данных будет содержать
инвентарный номер (максимум 4 цифры), описание (максимум 8 символов), количество
(4 цифры) и индикатор «тестовая часть» (4 цифры максимум => -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

Я абсолютно ничего не знаю о файлах Direct Access, поэтому просматривал пару разных ссылок, которые я нашел в Google (http://cee-ux49.cee.illinois.edu/cee490/public_html/pdfs_vgs/aL23_Direct_Access_Files.pdf , а также http://www.learncpp.com/cpp-tutorial/137-random-file-io/ в частности), но я не могу понять, как заставить это работать для этой конкретной программы.

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

#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 — это ставки. Затем файл должен посмотреть на последнее число в этой строке (3) и записать информацию для элемента с этим stockNumber (didgits) и так далее.

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

0

Решение

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

Я хотел бы создать структуры типа 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;
}

// ...
}

НОТА: Этот код написан на скорую руку и полностью не проверен и просто представлен как пример того, как можно решить эту проблему. Надеюсь, это даст вам некоторые идеи.

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

2

Другие решения

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

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

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

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

2

По вопросам рекламы [email protected]