Как использовать AnsiString для хранения двоичных данных?

У меня простой вопрос.

Я хочу использовать AnsiString в качестве контейнера для двоичных данных. Я в основном загружаю такие данные из TMemoryStream или TFileStream и сохраняю их обратно из AnsiString после некоторой обработки. Работает нормально, проблем с этим не обнаружил.

Но из того, что я видел, его использование вызывает споры о том, чтобы использовать вместо него Sysutils::TBytes. Почему? Sysutils::TBytes имеет гораздо меньше полезных методов, которые я могу использовать для управления данными, хранящимися внутри, например, AnsiString. Это явно недоработанный контейнер по сравнению с AnsiString.

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

Пример того, как я загружаю данные:

AnsiString data;
boost::scoped_ptr<TFileStream> fs(new TFileStream(FileName, fmOpenRead | fmShareDenyWrite));
data.SetLength(fs->Size);
fs->Read(data.c_str(), fs->Size);

Пример того, как я сохраняю данные:

// fs wants void * so I have to use data.data() instead of data.c_str() here
fs->Write(data.data(), data.Length());

Итак, должно быть безопасно хранить двоичные данные правильно?


person Coder12345    schedule 22.09.2014    source источник
comment
Рассмотрите возможность использования std::vector<unsigned char>   -  person M.M    schedule 23.09.2014


Ответы (1)


Я хочу использовать AnsiString в качестве контейнера для двоичных данных.

Одно слово - НЕ ДЕЛАТЬ! Это укусит вас когда-нибудь. Используйте более подходящий контейнер, например TBytes, TMemoryStream, std::vector<byte> и т. д.

Работает нормально, проблем с этим не обнаружил.

Считай, что тебе повезло. Начиная с C++Builder 2009, AnsiString поддерживает кодовую страницу, и это БУДЕТ вызывать преобразования данных, если вы не ОЧЕНЬ осторожны при передаче AnsiString. Рано или поздно вы, вероятно, ошибетесь, и это может привести к повреждению ваших двоичных данных.

Но из того, что я видел, его использование вызывает споры о том, чтобы вместо этого использовать Sysutils::TBytes. Почему?

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

В Sysutils::TBytes гораздо меньше полезных методов, которые я могу использовать для управления данными, хранящимися внутри, например AnsiString.

Вы не должны манипулировать двоичными данными как текстом для начала. И поскольку вы используете такие вещи, как Boost и STL, вам следует вместо этого рассмотреть возможность использования их бинарных контейнеров. Им доступно больше функций.

При этом в XE7 представлены некоторые новые функции для управления динамическими массивами в стиле Delphi (например, TBytes), включая вставки, удаления и конкатенации:

Операции, подобные строковым, поддерживаются в динамических массивах

Однако не похоже, чтобы эти новые функции попали в класс DynamicArray C++Builder (который TBytes является typedef).

Это явно недоработанный контейнер по сравнению с AnsiString.

AnsiString — это контейнер текстовых символов. Период. Всегда было, всегда будет. Люди ЗЛОУПОТРЕБЛЯЮТ, пользуясь тем фактом, что sizeof(char)==sizeof(byte). До определенного момента это работало, но в последние годы продолжать злоупотреблять этим стало опасно.

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

Это, а также тот факт, что Embarcadero постепенно отказывается от AnsiString с 2009 года. 8-битные строки отключены в мобильных компиляторах, и это только вопрос времени, когда компиляторы для настольных компьютеров последуют их примеру.

Почему вы хотите для начала манипулировать необработанными байтами как строками? Можете ли вы привести пример того, что вы можете сделать с AnsiString, но не можете сделать с TBytes?

Итак, должно быть безопасно хранить двоичные данные правильно?

В вашем конкретном примере да (и да, вы можете использовать c_str() вместо data() при вызове fs->Write()).

person Remy Lebeau    schedule 23.09.2014
comment
Ну, я мог бы адаптировать код к TBytes, я думаю, но я не уверен, что их подсчет ссылок защищен мьютексом, как UnicodeString или AnsiString в CB2010, чтобы быть безопасным для использования в многопоточности. Им также не хватает семантики копирования при записи, такой как AnsiString. И, как вы написали, вставки, удаления и конкатенации недоступны и так же просты в использовании, как в AnsiStrings, что является большим недостатком, хотя я мог бы сделать для этого функции замены, если они правильно мьютексированы. Я знаю о кодовой странице, но для строк я всегда использую UnicodeString и не назначаю AnsiString для UnicodeString. - person Coder12345; 24.09.2014
comment
Счетчики ссылок на динамические массивы защищены API-интерфейсами блокировки, как и для строк. - person Remy Lebeau; 24.09.2014