Jasmin Blanchette
Классы QString, QCString и QByteArray - это альтернативы для старомодных и ограниченных символьныхмассивов. Их надлежащее использование может сделать ваши приложения быстрее, меньше и более надежными. QString также приносит выгоды при интернационализации, использовании Юникода, а классы потоков типа QDataStream и QTextStream делают ввод/вывод более простым. Эта статья объясняет, как реализовать выгоды, предлагаемые этими классами.
QByteArray - Массив Символов |
Qt обеспечивает шаблонQMemArray
Массив QMemArray может содержать любые двоичные данные, включая '\0 ', и не должен кончаться на '\0 '. Это очень похоже на массив символов C-стиля, только лучше.
QByteArray - явно общедоступный класс. Это делает класс более эффективным в большинстве случаев, но может привести к тонким ошибкам. Стоит прочитать Общедоступные Классы, если Вы планируете использоватьQByteArray интенсивно.
Знайте, что стандарт C++ позволяет компилятору выбирать, является ли символ (char) со знаком (signed char) или без знака (unsigned char). Программы, которые имеют дело с символом, вероятно, предполагают, что символ со знаком. Многие компиляторы принимают параметры с командной строки для того, чтобы установить тип символа; например /j опция MSVC и С ++ 's - определяют символ как символ без знака. Вы можете использовать эти варианты, чтобы проверить ваши программы.
QByteArray - совершенный класс, чтобы хранить нетекстовые данные в памяти. Вы можете легко прочитать целый файл в QByteArray и выполнять итерации по массиву впоследствии:
QFile file( "Friday's jam session.mp3" ); if ( file.open(IO_ReadOnly) ) { QByteArray array = file.readAll(); file.close(); for ( int i = 0; i < array.size(); i++ ) { // etc. } }
Словарь С состоял из научно-технических терминов, которые не использовал никто, кроме ученых и техников. |
QCString класс сохраняет классический C-стиль '\0 '-законченной строки . QCString может использоваться, чтобы хранить любые '\0 '-законченные строки данных на 8 битов, типа Latin-1, EUC-KR, и расширенного двоично-десятичного кода.
Благодаря наследованию, QCString - это также и QByteArray. Строка с 5 знаками "HELLO" - также 6-символьный массив ""Hello\0"":
QCString s( "Hello" ); s.length(); // returns 5 s.size(); // returns 6
Если Вы конвертируете QCString в QByteArray:
QCString s( "Hello" ); QByteArray a = s.copy(); a.size(); // returns 6
(Мы вызываем copy (), чтобы получить копию массива.) Вы можете усечь массив, чтобы избавиться от '\0':
a.truncate( a.size() - 1 );
Если Вы преобразовываете QByteArray в QCString, требуется осторожность: Вы должны убедиться, чтоQByteArray - '\0 '- законченный. Если это не так, делайте следующее:
int n = a.size(); a.resize( n + 1 ); a[n] = '\0'; QCString s = a.data();
Исторически, QCString то же, что и 8 битов QString в Qt 1.x, и был сформирован главным образом, чтобы облегчить перенесение на Qt 2.0. Есть очень немного контекстов, где QCString предпочтителен для QByteArray или QString. В QCString главная выгода - то, что требуется только приблизительно половина памяти в отличие от QString.
QString - Строка Unicode |
Но почему Вы должны смешивать одно - и двухбайтовые значения так или иначе? |
QString класс хранит16-битовые Unicode строки. В отличие отQCString, они не '\0 '-законченные, и могут включить '\0'.
Преобразование из QString в QByteArray, QCString, или наоборот, может быть хитрым. Qt обеспечивает операторы и конструкторы, чтобы удобно было конвертировать из одного в другое (но не всегда).
1. Преобразование из QString в QCString.
QString состоящий полностью из Latin-1 знаков, (включая ASCII), может легко быть преобразован в QCString:
QString qstr( "Anders Еngstrцm <anders@telia.se>" ); QCString cstr = (const char *)qstr;
Но если QString не содержит Latin-1 знаков, результат неопределен.
Чтобы отключить это автоматическое (и возможно нежелательное) преобразование, Вы можете определить символ предпроцессора QT_NO_ASCII_CAST перед включением любого Qt заголовка. Это будет гарантировать вызов latin1 () явно:
QCString cstr = qstr.latin1();
Если Вы используете qmake, Вы можете отключать преобразование для вашего проекта, добавляя эту строку в .pro файл:
DEFINES += QT_NO_ASCII_CAST
Есть другие способы преобразования QString к QCString (см.документацию к классам QString и QTextCodec); функция utf8 () имеет преимущество сохранения всей информации:
QCString cstr = qstr.utf8();
2. Преобразование из QCString в QString.
QCString не передает специфические коды. Если Вы храните Latin - 1 вQCString, преобразование в Юникод тривиально:
QCString cstr( "Carl Friedrich GauЯ <gauss@gmx.de>" ); QString qstr = cstr;
Если Вы используете другие кодировки, кроме Latin-1, это автоматическое преобразование опасно. Чтобы отключить это, определитесимвол QT_NO_CAST_ASCII препроцессора(не перепутайте с QT_NO_ASCII_CAST). Вы тогда должны вызвать fromLatin1 () явно, чтобы конвертировать Latin-1QCString кQString:
QString qstr = QString::fromLatin1( cstr );
Подобная функция существует для строк в формате UTF-8.
Самый простой способ поребразовывать QString в QByteArray - подход редукции: конвертируйтеQString вQCString, затем конвертируйте QCString в QByteArray:
QString qstr( "Anders Еngstrцm <anders@telia.se>" ); QByteArray array = QCString( qstr );
Окончание QByteArray будет иметь '\0' признак конца.
Qt обращает QByteArray в QString автоматически:
QByteArray array; array.assign( "Hello\0World", 11 ); QString str = array;
Конструктор останавливается в первом '\0' символе. В вышеупомянутом фрагменте кода, str - строка из 5 символов "HELLO",а не строка из 11 символов ""HELLO \\ 0World"".
* |
* |
* |
|
Преобразование от одного типа к другому может быть опасно, потому что компьютер не может знать мнение программиста, чтобы установить соответствующую кодировку. Следующие правила могут помочь Вам:
Теперь давайте увидим, как эти вещи касаются ввода - вывода.
QDataStream- Потоки двоичных данных |
Мы имеем два выбора, или чтобы напасть на ввод - вывод сразу и закончить его, или откладывать ввод - вывод до конца.
Никакая из перспектив не очень привлекательна. |
QDataStream класс может использоваться, чтобы читать и записывать двоичные данные в файл или в некоторое другое "устройство" ввода - вывода. Пример, как записать 32-разрядное целое число без знака 0x92025428 в небольшой endian файл с названием "nitty":
QFile file( "nitty" ); if ( file.open(IO_WriteOnly) ) { QDataStream out( &file ); out.setByteOrder( QDataStream::LittleEndian ); out << (Q_UINT32)0x92025428; }
Пример, как читать 16-разрядное целое число со знаком в большом endian (значение по умолчанию) из файла, названного "gritty":
QFile file( "gritty" ); if ( file.open(IO_ReadOnly) ) { QDataStream in( &file ); Q_INT16 n; in >> n; }
QDataStream поддерживаетмного типов: Q_INT8, Q_INT16, Q_INT32, Q_UINT8, Q_UINT16, Q_UINT32, float, double, char *, QBitArray .QByteArray, QCString, QString, QVariant, и еще многие. Полный список доступен вФормате QDataStream Операторов.
Наш первый пример будет демонстрировать, как сохранить все свойстваQObject в устройстве ввода - вывода (обычно файл) и как загрузить их впоследствии. Вот код:
const Q_UINT32 MagicNumber = 0x1A7D3EF6; void writeProperties( QObject *obj, QIODevice *device ) { QDataStream out( device ); out << (Q_UINT32)MagicNumber << (Q_UINT8)out.version(); int n = obj->metaObject()->numProperties( true ); for ( int i = 0; i < n; i++ ) { const QMetaProperty *prop = obj->metaObject()->property( i, true ); if ( prop->writable() ) { out << prop->name() << obj->property( prop->name() ); } } }
При вводе или выводе сложных типов типаQVariant очень важно удостовериться, что та же самая версия потока используется для чтения и записи.:
QDataStream out( device ); out.setVersion( 5 ); ... QDataStream in( device ); in.setVersion( 5 );
Недостаток непосредственного задания данных в том, что приложение не будет изменяться в усовершенствованной Qt 3.2 или более поздних версиях - например, при добавлении нового цвета в QColorGroup.
Пример, как считать свойства, записанные writeProperties ():
void readProperties( QObject *obj, QIODevice *device ) { QDataStream in( device ); Q_UINT32 magic; Q_UINT8 version; in >> magic; if ( magic != MagicNumber ) { qWarning( "Not property data" ); return; } in >> version; if ( in.version() < version ) { qWarning( "Data is from a newer version" ); return; } in.setVersion( version ); QCString name; QVariant value; while ( !in.atEnd() ) { in >> name; if ( name.isNull() ) break; in >> value; obj->setProperty( name, value ); } }
В следующем фрагменте кода, мы используем writeProperties () и readProperties (), чтобы сохранить свойства окна между сеансами:
QFrame *frame = new QFrame( parent ); QFile file( "properties" ); if ( file.open(IO_ReadOnly) ) readProperties( frame, &file ); ... QFile file( "properties" ); if ( file.open(IO_WriteOnly) ) writeProperties( frame, &file ); delete frame;
Ширина и высота изображения - первые два поля заголовка изображения ("IHDR"). Вот законченный код программы Qt, которая распечатывает ширину и высоту изображений PNG, указанных в командной строке:
#include <qbuffer.h> #include <qcstring.h> #include <qdatastream.h> #include <qfile.h> #include <qsize.h> QSize getPngImageSize( QIODevice *device ) { Q_UINT32 width = 0; Q_UINT32 height = 0; char signature[8]; char chunkType[4]; QDataStream in( device ); in.readRawBytes( signature, 8 ); if ( memcmp(signature, "\211PNG\r\n\32\n", 8) == 0 ) { while ( !in.atEnd() ) { Q_UINT32 length; in >> length; in.readRawBytes( chunkType, 4 ); if ( memcmp(chunkType, "IHDR", 4) == 0 ) { in >> width >> height; break; } // jump to the next chunk device->at( device->at() + length + 4 ); } } return QSize( width, height ); } int main( int argc, char **argv ) { if ( argc < 2 ) { qWarning( "Usage: pngsize file1.png etc." ); return 1; } for ( int i = 1; i < argc; i++ ) { QFile file( QFile::decodeName(argv[i]) ); if ( file.open(IO_ReadOnly) ) { QSize size = getPngImageSize( &file ); qWarning( "%s: %d x %d", argv[i], size.width(), size.height() ); } else qWarning( "Cannot open file '%s'", argv[i] ); } return 0; }
(Если скорость не важна, и Qt конфигурирован с поддержкой PNG, Вы можете позволитьQImage делать трудную работу:
QSize size = QImage( argv[i] ).size();
Но это не демонстрирует QDataStream.)
Теперь давайте предположим, что нам внедрили изображение PNG в наше приложение, используя qembed или подобный инструмент:
static const char png_data[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, ... 0x44, 0x75, 0x74, 0x63, 0x68, 0x6d, 0x61, 0x6e, 0x44, 0xae, 0x42, 0x60, 0x82 };
Как мы можем определить размер этого изображения, не создаваяQImage? Ответ следует из этих четырех фактов:
Пример, как преобразовать эти идеи в выполняющийся код:
QByteArray array; array.setRawData( png_data, sizeof(png_data) ); QBuffer buffer( array ); buffer.open( IO_ReadOnly ); QSize size = getPngImageSize( &buffer ); array.resetRawData( png_data, sizeof(png_data) );
QTextStream Текст Потоков |
QTextStream читает и пишет данные в текстовый файл или в любое другое устройство ввода - вывода. Например, как записать "Hello {w|0c o} rld! " \\ "n" в файл "greetings":
QFile file( "greetings" );
if ( file.open(IO_WriteOnly) ) { QTextStream out( &file );
Главная особенность QTextStream - то, что можно использовать QTextCodec, чтобы конвертировать данные относительно устройства ввода - вывода на основе байта и 16-разрядного Юникода в QString класс. По умолчанию используется кодирование в 8 битов, предописанное языком (Latin-1 в большинстве Европы).
К сожалению, поддержка QTextCodec делает QTextStream намного медленнее, чем двоичный ввод - вывод. Trolltech планирует сделать QTextStream быстрее в Qt 4.0.
stream.setEncoding( QTextStream::Latin1 );
Если Вы записываете XML, Вы захотите также применять
stream.setEncoding( QTextStream::UnicodeUTF8 );
или
stream.setEncoding( QTextStream::Unicode );
QTextStream может даже оперироватьс QString. Два удобных подкласса - QTextIStream и QTextOStream - делают это очень простым:
QString str; QTextOStream( &str ) << 22 << " " << "trees"; // str == "22 trees" int n; QString thing; QTextIStream( &str ) >> n >> thing; // n == 22, thing == "trees"
Большая часть того, что Вы уже знаете про
QTextOStream qout( stdout ); qout << oct << 31 << " = " << dec << 25 << endl;
Статья, генерирующая XML, представляет приложениеQTextStream .
Copyright © 2003 Trolltech. |