LINUX.ORG.RU

Объединение списка имён файлов в одну строку с возможностью обратной операции


0

1

Здрасьте. Так получилось, что мне внутри программы приходится передавать список имён файлов одной строкой (это связано со способом работы QtSingleApplication). Сейчас сделано так:

/* Калька с магического числа из файлов моей
 * программы -- 0xD3ADB00B.
 * Тут могло быть любое другое слово, не применяемое
 * нормальными людьми в названиях файлов. */
    static const QString k_magic_word = "DEADBOOBISSODEAD";
// Объединяем:
    QStringList files = app.arguments();
    files.removeAt(0);
    QString message = files.join(k_magic_word);
// Разъединяем:
    QStringList file_names;
    file_names = message.split(k_magic_word);

Короче, разделяя файлы этим словом, вероятность того, что операция пройдёт не успешно (то есть что какой-то файл содержал в себе это слово) пренебрежительно мала.

Но не нравится мне такое дело. Туповато как-то.

Как нормальные люди это делают?

★★★★★

Блин, пока писал, сам допёр. Надо экранировать пробелы. Но надо сначала экранировать экранирующий знак.

Для объединения заменяем все «/» на «//», все " " на «/ ».

Для раздъединения заменяем все «/ » на пробелы и «//» на «/».

Так?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

да хотя бы, если проявить фантазию вариантов милион. Возникает вопрос а ты уверен, что QStringList передать никак нельзя?

erfea ★★★★★
()
Ответ на: комментарий от erfea

Никак, всё дело в QtSingleApplication.

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

int main(int argc, char **argv)
{
    Application app(argc, argv);

    QStringList files = app.arguments();
    files.removeAt(0);
    QString message = files.join("DEADBOOBISSODEAD");
    
    // пытаемся послать сообщение уде открытому экземпляру программы
    if (app.sendMessage(message)) {
        return 0;
    }
    
    // открытого экземпляра нету? значит, мы первый.
    // будем читать входящие сигналы при попытках открыть другие экземпляры
    QObject::connect(&app, SIGNAL(messageReceived(QString)),
                     &app, SLOT(handleMessage(QString)));

    // ...

    // обработаем наши аргументы
    app.handleMessage(message);

    // ...
    return app.exec()
}

sendMessage — это метод QtSingleApplication, как я понял он записывает сообщение в файл и ждёт, не исчезнет ли оно оттуда. Если исчезнет, то возвращает true — это значит, что экземпляр такой программы уже открыт.

В данном случае уже запущенный экземпляр дооткроет те файлы, которые передали в качестве аргументов.

Obey-Kun ★★★★★
() автор топика

>Короче, разделяя файлы этим словом

Разделяй файлы каким-нибудь непечатемым символом, будь мужиком!

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Я - нет, но файлы с такими именами запросто получаются, если локаль - какой-нибудь дебильный юникод.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Obey-Kun

Вот такой:

struct listentry{
char *filename;
struct listentry *prev;
struct listentry *next;
}

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от yoghurt

А при чем здесь нули вообще? Нуль - как бы признак конца строки. Так что использовать его в качестве разделителя не получится. (точнее, это можно сварганить, но придется всегда точно контролировать длину строки)

Eddy_Em ☆☆☆☆☆
()

По стандарту в имени файла не может быть символа \0. Вот им и разделяй. QString нормально ест нули внутри себя. Разве что sendMessage может быть их не переварит, это проверить надо. Но вообще должно работать, иначе бы разрабы Qt так и написали бы - мол sendMessage принимает char*, а не qstring.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Нафига вообще список передавать? Его спокойненько можно хранить в разделяемой памяти, а в сигнале посылать идентификатор выделенной области памяти.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Obey-Kun

Ну тогда как самый простой вариант экранируй все пробелы в именах файлов, и раздели пробелом, все не экранированные - разделители.

erfea ★★★★★
()
Ответ на: комментарий от Eddy_Em

Именно. Такой трюк юзался где-то в винде, например

yoghurt ★★★★★
()

передавай длину строки перед каждой строкой :)

arsi ★★★★★
()

В Unix имя файла не может содержать «\0» и «/». Так что если у тебя именно имена, а не пути, то можно использовать для их разделения слэш без всякого экранирования.

Relan ★★★★★
()
Ответ на: комментарий от Relan

> можно использовать для их разделения слэш без всякого экранирования.

т.е. карл/маркс/фридрих/энгельс — четыре разные файла? ;)

arsi ★★★★★
()
Ответ на: комментарий от Obey-Kun

> А в других ОС?

Из других ОС я знаю только DOS/Windows, а там «/» также нельзя в именах файлов использовать.

Relan ★★★★★
()

Передавай в xml - будет мощно.
Еще можно в base64, разделенные запятыми. Можно преобразовывать строки в массив байт, а из них делать снова строки, но с байтами в 16-ричном представлении.
Легче всего - «ДЛИНА_В_СИМВОЛАХ1Строка1ДЛИНА_В_СИМВОЛАХ2Строка2...».

note173 ★★★★★
()
Ответ на: комментарий от note173

> длину, соответственно, нормализовать нулями до размера, вмещающего максимальную длину файла

зачем такие извраты, если длину можно задать одним символом? там же символы 16-битные, а имени файла нулевой длины вроде как не бывает :) получится почти как в старом паскале :)

arsi ★★★★★
()
Ответ на: комментарий от o

>> В Unix имя файла не может содержать «\0» и «/».

В Linux «/» точно может.

А вас не смущает, что «/» используется в качестве разделителя компонентов пути и все системные вызовы интерпретируют его именно так? :) Вообще, вот тут всё расписано: http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words

Relan ★★★★★
()
Ответ на: комментарий от Relan

Тем не менее, такие файлы могут существовать. Кстати, что вы будете делать если обнаружите у себя в $HOME такой файл? ;)

o
()

Поступите по принципу SMTP - обьявите например ";" разделителем, а чтобы указать в имени файла ";" используйте ";;", то есть

file1;file2;file3 это три файла
file;;file2;file3 это два файла, «file1;file2» и '«file3»

Nastishka ★★★★★
()
Ответ на: комментарий от Obey-Kun

А вот у меня такой вопрос появился. Пусть у нас два файла с именами «abc;» и «def». Тогда при записи в одну строку получается «abc;;;def». Но ведь такая же строка получается и для файлов с именами «abc» и ";def". Как разруливают такую неоднозначность? Или я где-то ступил?

kalenkov
()
Ответ на: комментарий от legolegs

По стандарту в имени файла не может быть символа \0. Вот им и разделяй. QString нормально ест нули внутри себя. Разве что sendMessage может быть их не переварит, это проверить надо. Но вообще должно работать, иначе бы разрабы Qt так и написали бы - мол sendMessage принимает char*, а не qstring.

а что с char* не так? вот уж кому покласть что внутри лежит, так это char*

shty ★★★★★
()
Ответ на: комментарий от Relan

> что вы будете делать если обнаружите у себя в $HOME такой файл?

Запущу fsck. :)

недолго мучалась лошадка в телефонных проводах

//отмаунтить не забудь

shty ★★★★★
()

в копилку предложений: :)

рандомно выбери символ-разделитель (их 64к, есть из чего выбирать) и проверь, содержит ли его хоть один из файлов. если есть — генерь следующий и т.п. как найдёшь уникальный, используй его как разделитель файлов, но первая запись должна быть пустой (т.е. первый символ в строке — разделитель).
QStringList list -> QString string: string = separator + list.join(separator).
QString string -> QStringList list: list = string.split(string[0], QString::SkipEmptyParts).
как-то так :)

arsi ★★★★★
()
Ответ на: комментарий от Zenom

> Пихай имена в JSON. Для этого и либы готовые есть.

ППКС. Нечего изобретать велосипеды.

rival ★★
()

вот такого не получится?

// из костылей выбрал бы разделение 0-ём

backbone ★★★★★
()
Ответ на: комментарий от shty

Указателю конечно пофиг на что указывать, хоть на пивную, хехе. А вот всякие strcpy имеют своё мнение о значении \0.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Указателю конечно пофиг на что указывать, хоть на пивную, хехе. А вот всякие strcpy имеют своё мнение о значении \0.

use memmove/memcpy luke :)

shty ★★★★★
()
Ответ на: комментарий от visual_pipe

он там есть, но разделитель всё равно надо указывать.

Obey-Kun ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.