Форум программистов, компьютерный форум CyberForum.ru

Мой класс для работы с файлами - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 16, средняя оценка - 4.88
Hagrael
БТР - мой друг
 Аватар для Hagrael
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
21.06.2012, 09:58     Мой класс для работы с файлами #1
Здравствуйте! Я попробовал сделать свой класс для работы с файлами и показать его здесь с целью узнать, что я в нем сделал не так

Класс называется File.
В нем один закрытый член - fstream file. Это файл, с которым программист будет работать.

У класса присутствуют следующие функции:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
inline void open (char* name, long int mode);
// Функция открывает файл для того, чтобы программист мог дальше с ним
// работать. Она принимает 2 аргумента:
// name - указатель на строку с именем открываемого файла или путем к нему;
// mode - режим, в котором файл открывается (о том, как его выбирать,
// см. далее)
 
inline bool openAndCheck (char* name, long int mode);
// Функция делает то же, что и предыдущая, но после проделанного
// возвращает значение true, если все прошло успешно или же
// false, если произошла ошибка.
 
inline bool isOpened ();
// Функция возвращает true, если файл открыт или же false, если он закрыт.
 
inline void close ();
// Функция закрывает открытый файл.
 
inline void readContent (type* pointer, int length);
// Шаблонная функция. Считывает length байтов и записывает их по
// адресу, на который указывает pointer.
 
inline void readString (char* pointer, int length);
// Функция записывает в строку, на которую указывает указатель pointer
// length символов и добавляет после них символ завершения строки ('\0').
 
inline void read (type* pointer);
// Шаблонная функция. Записывает информацию в переменную, расположенную
// по адресу, на который указывает указатель pointer. Считывает ровно столько,
// сколько способна вместить переменная. Иначе говоря, считывает sizeof(type)
// байт.
 
inline void read (type* array, int length);
// Функция считывает количество байт, равное количеству байт, занимаемых
// length ячейками массива типа type и записывает их в массив array. Функция шаблонная.
 
inline void readBlock (type* pointer);
// Шаблонная функция. Читает блок из файла и помещает его в переменную по адресу,
// на который указывает pointer. Под блоком подразумевается все,
// находящееся до разделительного символа (табуляции, пробела и т. д.).
 
inline void writeContent (type* pointer, int length);
// Функция записывает length байт, расположенных по адресу,
// на который указывает переменная pointer, в файл. Функция шаблонная.
 
inline void write (type* pointer);
// Шаблонная функция. Записывает переменную, на которую указывает
// указатель pointer, в файл.
 
inline void write (type* array, int length);
// Шаблонная функция. Записывает массив array длинной length в файл.
 
inline void writeAsText (type variable);
// Шаблонная функция. Записывает переменную variable в файл в текстовом виде.
 
inline void writeAsText (type* pointer);
// Шаблонная функция. Делает все то же самое, что и предыдущий вариант
// этой функции, но принимает в качестве аргумента не саму переменную,
// а указатель на нее.
 
inline int getPointerPosition ();
// Функция возвращает номер символа, на который сейчас "смотрит"
// указатель файла (я не знаю, как это точно называется :)).
 
inline void setPointerPosition (int position);
// Функция перемещает указатель файла на символ, чей номер position.
 
inline bool isAllRight ();
// Функция возвращает true, если все в порядке, или же false, если нет.
Конструкторы и деструкторы класса:
C++
1
2
3
4
5
6
7
8
inline File ();
// Этот конструктор ничего не делает.
 
inline File (char* name, long int mode);
// Этот конструктор вызывает функция open с параметрами name и mode
 
inline ~File ();
// Деструктор вызывает функцию close.
Все функции имеют модификатор inline, потому что все они очень короткие, и на мой взгляд, нет нужды ради них выделять отдельное место в стеке и тратить на это время.

Так каким же образом можно указать параметр mode функции open? Первый способ: такой же, как и у функции fstream::open:
C++
1
File file(name, ios::in | ios::out | ios::ate);
Но есть схожий, но на мой взгляд, более удобный способ:
C++
1
File file(name, File::forInput | File::forOutput | File::moveToEnd)
Здесь показано, какие флаги ios идентичны флагам класса File:
C++
1
2
3
4
5
6
File::forAppend = ios::app
File::moveToEnd = ios::ate
File::asBinary = ios::binary
File::forInput = ios::in
File::forOutput = ios::out
File::truncate = ios::trunc
Пример использования класса:
C++
1
2
3
4
5
6
7
8
File file("text.txt", File::asBinary | File::truncate | File::forOutput | File::forInput);
 
int n = 5;
file.writeAsText(n);
file.setPointerPosition(0);
char s[2];
file.readString(s, 1);
std::cout << s;
Вот так выглядит код класса:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <fstream>
 
class File {
    private:
        std::fstream file;
    public:
        // конструкторы и деструктор:
 
        inline File () {}
 
        inline File (char* name, long int mode) {
            open(name, mode);
        }
 
        inline ~File () {
            close();
        }
 
 
        // открытие и закрытие файла:
 
        inline void open (char* name, long int mode) {
            file.open(name, std::ios::openmode(mode));
        }
 
        inline bool openAndCheck (char* name, long int mode) {
            open(name, mode);
            return isAllRight();
        }
 
        inline bool isOpened () {
            return file.is_open();
        }
 
        inline void close () {
            file.close();
        }
 
        // чтение файла:
 
        template <class type> inline void readContent (type* pointer, int length) {
            file.read(reinterpret_cast<char*>(pointer), length);
        }
 
        inline void readContent (char* pointer, int length) {
            file.read(pointer, length);
        }
 
        inline void readString (char* pointer, int length) {
            file.read(pointer, length);
            *(pointer+length) = '\0';
        }
 
        template <class type> inline void read (type* pointer) {
            readContent(reinterpret_cast<char*>(pointer), sizeof(pointer));
        }
 
        template <class type> inline void read (type* array, int length) {
            readContent(reinterpret_cast<char*>(array), sizeof(type)*length);
        }
 
        template <class type> inline void readBlock (type* pointer) {
            file >> *pointer;
        }
 
        // запись в файл:
 
        template <class type> inline void writeContent (type* pointer, int length) {
            file.write(reinterpret_cast<char*>(pointer), length);
        }
 
        inline void writeContent (char* pointer, int length) {
            file.write(pointer, length);
        }
 
        template <class type> inline void write (type* pointer) {
            writeContent(reinterpret_cast<char*>(pointer), sizeof(type));
        }
 
        template <class type> inline void write (type* array, int length) {
            writeContent(reinterpret_cast<char*>(array), sizeof(type)*length);
        }
 
        template <class type> inline void writeAsText (type variable) {
            file << variable;
        }
 
        template <class type> inline void writeAsText (type* pointer) {
            file << *pointer;
        }
 
        // перемещение и получение позиции указателя:
 
        inline int getPointerPosition () {
            return file.tellp();
        }
 
        inline void setPointerPosition (int position) {
            file.seekp(position);
        }
 
        // проверка состояния файла:
 
        inline bool isAllRight () {
            return file.good();
        }
 
        // флаги для выбора режима работы с файлом:
 
        const static long int forAppend = 1L << 0;
        const static long int moveToEnd = 1L << 1;
        const static long int asBinary = 1L << 2;
        const static long int forInput = 1L << 3;
        const static long int forOutput = 1L << 4;
        const static long int truncate = 1L << 5;
};
С радостью выслушаю все пожелания и замечания.

Добавлено через 17 часов 30 минут
Немного подкорректировал стиль названий данных: названия переменных начинаются, как и раньше, с маленькой буквы, а названия функций теперь начинаются с большой буквы.

Добавил новую функцию.
C++
1
2
3
4
5
6
7
inline void ReadString (char* pointer);
// Функция считывает строку с файла и записывает ее в строку,
// расположенную по адресу, на который указывает pointer.
// Ее отличие от функции ReadString (char* pointer, int length)
// заключается в том, что этой функции не нужно сообщать
// длину считываемой строки. Строка считается оконченной,
// когда в файле встретится символ окончания строки - '\0'
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.06.2012, 09:58     Мой класс для работы с файлами
Посмотрите здесь:

C++ Функции для работы с текстовыми файлами
Программой, содержащая класс, структуры и функции работы с файлами. Синтаксических ошибок нет, но работа прерывается и ничего не выводится на экран. C++
Ищу 2 оператора для работы с файлами C++
C++ Программа для работы с бинарными файлами
C++ Элементарный класс для работы с файлами, компилятор выдает ошибку, что не так с private
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
sandye51
программист С++
 Аватар для sandye51
677 / 579 / 39
Регистрация: 19.12.2010
Сообщений: 2,016
21.06.2012, 10:23     Мой класс для работы с файлами #2
собственно зачем нужна обертка для std::fstream? когда он сам удобен для работы
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
21.06.2012, 10:35     Мой класс для работы с файлами #3
Во первых, соглашусь с предыдущим оратором.
Во вторых, класс не добавляет функциональности, т.е. он бесполезен. Но кое-что можно поменять, чтобы смысл появился. Например:
C++
1
2
3
template <class type> inline void writeContent (type* pointer, int length) {
            file.write(reinterpret_cast<char*>(pointer), length);
        }
заменить на
C++
1
2
3
template <class type> inline void writeContent (const type& pointer) {
            file.write(reinterpret_cast<char*>(&pointer), sizeof(type));
        }
Так ты сможешь записывать POD объекты не указывая размер вручную, т.е. меньше шансов ошибиться. Прочие метода аналогично подправить можно.
Кроме того, перед каждым объектом рекомендую сохранять размер этого объекта. А ещё лучше и версию его сохранять.
Hagrael
БТР - мой друг
 Аватар для Hagrael
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
21.06.2012, 11:33  [ТС]     Мой класс для работы с файлами #4
Обернуть fstream я решил, потому что мне не нравится то, как названы встроенные данные и потому что в самом классе fstream нету некоторых функций, которые я реализовал в своем классе.

Про передачу по ссылке я тоже думал. Вначале я создал по 2 экземпляра каждой функции: один для работы с указателями, другой - для работы со ссылками. Но после решил, что смысл у этих функций будет один и тот же, хотя программисту передача по ссылке будет удобнее, и удалил вариант с ссылками.

Цитата Сообщение от Deviaphan Посмотреть сообщение
Так ты сможешь записывать POD объекты не указывая размер вручную, т.е. меньше шансов ошибиться
А у меня вроде бы и так указывать размер переменной не нужно:
C++
1
2
3
File file(...);
int n = 5;
file.write(&n);
Цитата Сообщение от Deviaphan Посмотреть сообщение
Кроме того, перед каждым объектом рекомендую сохранять размер этого объекта. А ещё лучше и версию его сохранять.
А вот этого я не понял

Добавлено через 1 минуту
Вот, кстати, последний вариант класса:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <fstream>
 
class File {
    private:
        std::fstream file;
    public:
        // конструкторы и деструктор:
 
        inline File () {}
 
        inline File (char* name, long int mode) {
            Open(name, mode);
        }
 
        inline ~File () {
            Close();
        }
 
 
        // открытие и закрытие файла:
 
        inline void Open (char* name, long int mode) {
            file.open(name, std::ios::openmode(mode));
        }
 
        const static long int forAppend = 1L << 0;
        const static long int moveToEnd = 1L << 1;
        const static long int asBinary = 1L << 2;
        const static long int forInput = 1L << 3;
        const static long int forOutput = 1L << 4;
        const static long int truncate = 1L << 5;
 
        inline bool OpenAndCheck (char* name, long int mode) {
            Open(name, mode);
            return IsAllRight();
        }
 
        inline bool IsOpened () {
            return file.is_open();
        }
 
        inline void Close () {
            file.close();
        }
 
        // чтение файла:
 
        template <class type> inline void ReadContent (type* pointer, int length) {
            file.read(reinterpret_cast<char*>(pointer), length);
        }
 
        inline void ReadContent (char* pointer, int length) {
            file.read(pointer, length);
        }
 
        inline void ReadString (char* pointer, int length) {
            file.read(pointer, length);
            *(pointer+length) = '\0';
        }
 
        inline void ReadString (char* pointer) {
            char ch;
            int i = 0;
 
            ReadContent(&ch, 1);
            while (ch != '\0') {
                *(pointer+i) = ch;
                i++;
                ReadContent(&ch, 1);
            }
            *(pointer+i) = '\0';
        }
 
        template <class type> inline void Read (type* pointer) {
            ReadContent(reinterpret_cast<char*>(pointer), sizeof(pointer));
        }
 
        template <class type> inline void Read (type* array, int length) {
            ReadContent(reinterpret_cast<char*>(array), sizeof(type)*length);
        }
 
        template <class type> inline void ReadBlock (type* pointer) {
            file >> *pointer;
        }
 
        // запись в файл:
 
        template <class type> inline void WriteContent (type* pointer, int length) {
            file.write(reinterpret_cast<char*>(pointer), length);
        }
 
        inline void WriteContent (char* pointer, int length) {
            file.write(pointer, length);
        }
 
        inline void WriteString (char* pointer) {
            int i = 0;
            while (*(pointer+i) != '\0') {
                WriteContent(pointer+i, 1);
                i++;
            }
            WriteContent(pointer+i, 1);
        }
 
        template <class type> inline void Write (type* pointer) {
            WriteContent(reinterpret_cast<char*>(pointer), sizeof(type));
        }
 
        template <class type> inline void Write (type* array, int length) {
            WriteContent(reinterpret_cast<char*>(array), sizeof(type)*length);
        }
 
        template <class type> inline void WriteAsText (type variable) {
            file << variable;
        }
 
        template <class type> inline void WriteAsText (type* pointer) {
            file << *pointer;
        }
 
        // перемещение и получение позиции указателя:
 
        inline int GetPointerPosition () {
            return file.tellp();
        }
 
        inline void SetPointerPosition (int position) {
            file.seekp(position);
        }
 
        inline void SetPointerPosition (int position, long int base) {
            file.seekp(position, std::ios_base::seekdir(base));
        }
 
        const static long int beginning = 0L;
        const static long int currentPosition = 1L << 0;
        const static long int end = 1L << 1;
 
        // проверка состояния файла:
 
        inline bool IsAllRight () {
            return file.good();
        }
};
Добавлено через 1 минуту
Скоро разобью его на 2 класса: FileForInput и FileForOutput, а после с помощью наследования заново создам этот класс.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
21.06.2012, 11:48     Мой класс для работы с файлами #5
Цитата Сообщение от Hagrael Посмотреть сообщение
А у меня вроде бы и так указывать размер переменной не нужно
Тогда WriteContent лучше не открытой сделать. Хотя пофиг.)

Цитата Сообщение от Hagrael Посмотреть сообщение
А вот этого я не понял
было struct A{ int a; };, стало struct A{ int a; int b; }; и всё. Считать уже не сможешь.

Строки 136, 137. Почему просто не написать 1 и 2?

Ну и по поводу имени аргумента length. На самом деле это количество элементов в массиве, так что лучше назвать count или типа того.

И при смене компилятора или режимов компиляции, чтение может стать невозможным. Т.е. размер структуры (в общем случае) не равен сумме размеров данных, в ней имеющихся.
Hagrael
БТР - мой друг
 Аватар для Hagrael
331 / 273 / 2
Регистрация: 07.01.2010
Сообщений: 1,932
21.06.2012, 12:11  [ТС]     Мой класс для работы с файлами #6
Цитата Сообщение от Deviaphan Посмотреть сообщение
огда WriteContent лучше не открытой сделать. Хотя пофиг.)
В принципе можно, но все же лучше пусть будет. Она нужна на случай, если человек хочет написать информацию, располагающуюся по некому адресу и имеющую некоторую длину. Т. е. например, с помощью этой функции можно записать информацию, на которую указывает указатель типа void. Хотя я не знаю, где это может понадобиться.

Цитата Сообщение от Deviaphan Посмотреть сообщение
Строки 136, 137. Почему просто не написать 1 и 2?
Просто хотелось показать, что это именно флаги, а не простые числа

Цитата Сообщение от Deviaphan Посмотреть сообщение
Ну и по поводу имени аргумента length. На самом деле это количество элементов в массиве, так что лучше назвать count или типа того.
В JS длина массива обозначается как length, по-моему, это тоже одно из стандартных названий.

Цитата Сообщение от Deviaphan Посмотреть сообщение
И при смене компилятора или режимов компиляции, чтение может стать невозможным. Т.е. размер структуры (в общем случае) не равен сумме размеров данных, в ней имеющихся.
Тогда нужно записывать в структуру по очереди каждый параметр
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
21.06.2012, 12:15     Мой класс для работы с файлами #7
Цитата Сообщение от Hagrael Посмотреть сообщение
Тогда нужно записывать в структуру по очереди каждый параметр
Именно так.
Либо сохранять размер и версию структуры и при чтении проверять. А ещё лучше, чтобы структура сама себя сохраняла.
novi4ok
549 / 502 / 8
Регистрация: 23.07.2009
Сообщений: 2,359
Записей в блоге: 1
21.06.2012, 12:18     Мой класс для работы с файлами #8
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от Hagrael Посмотреть сообщение
Но после решил, что ... программисту передача по ссылке будет удобнее, и удалил вариант с ссылками.
и правильно! так ему, программисту, и надо!
Deviaphan
21.06.2012, 12:22
  #9

Не по теме:

Цитата Сообщение от novi4ok Посмотреть сообщение
так ему, программисту, и надо!
Только сейчас понял всю соль вышесказанного.

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.06.2012, 13:11     Мой класс для работы с файлами
Еще ссылки по теме:

Библиотека для работы с файлами C++
C++ C++ DLL для работы с php файлами
Класс для работы с файлами C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Hagrael
21.06.2012, 13:11  [ТС]     Мой класс для работы с файлами
  #10

Не по теме:

Yandex
Объявления
21.06.2012, 13:11     Мой класс для работы с файлами
Ответ Создать тему
Опции темы

Текущее время: 11:48. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru