Qt передать файл по сети

Обновлено: 05.07.2024

На этом уроке мы рассмотрим работу с файлами и каталогами в Qt5. Для этого мы будем использовать следующие классы:

QFile , QDir и QFileInfo — основные классы для работы с файлами в Qt5;

QFile — предоставляет интерфейс для чтения и записи информации в файлы;

QDir — обеспечивает доступ к структуре каталогов и к их содержимому;

QFileInfo — предоставляет информацию о файле, включая его имя и расположение в файловой системе, время доступа и изменения, имя владельца файла и текущие разрешения.

Размер файла

Для определения размера файла в классе QFileInfo предусмотрен метод size():

// Имя файла передается в качестве аргумента в нашу программу qWarning ( "The file does not exist" ) ; // если файл не найден, то выводим предупреждение и завершаем работу программы qint64 size = fileinfo . size ( ) ; // qint64 - это тип данных, который гарантированно будет 64-битным на всех платформах, поддерживаемых Qt

Для запуска программы проделайте следующие шаги:

ПОДГОТОВКА:

Шаг №1: Скомпилируйте вашу программу. Для этого выберите в меню "Сборка" > "Собрать всё" (или нажмите Ctrl+Shift+B ).

Шаг №2: Зайдите в папку, где лежит ваш Qt-проект (у меня он расположен в C:\dev\Qt_Project ).

Шаг №3: После выполнения первого шага у вас должна появиться еще одна папка, в которой будет создан исполняемый файл программы. Т.к. я использую компилятор MinGW 32-bit и режим компиляции Debug, то при компиляции проекта Qt автоматически создал папку build-My_QtApplication-Desktop_Qt_5_13_0_MinGW_32_bit-Debug .

Шаг №4: Зайдите в папку debug (она находится внутри папки, созданной на шаге №3).

Шаг №5: Найдите *.exe-файл вашей программы (у меня это file_size.exe ).

Шаг №6: Скопируйте этот файл в папку к соответствующему компилятору (напомню, т.к. я использовал компилятор MinGW 32-bit, то у меня этот путь выглядит следующим образом: C:\Soft\Qt\5.13.0\mingw73_32\bin ).

ЗАПУСК ПРОГРАММЫ:

Шаг №7: Откройте командную строку.

Шаг №8: Перейдите в папку, указанную в шаге №6 ( cd C:\Soft\Qt\5.13.0\mingw73_32\bin ).

Шаг №9: Запустите свою программу, передав ей в качестве параметра имя любого файла (у меня этим файлом оказалась эта же программа, поэтому в моем случае команда была следующей: file_size.exe file_size.exe ).

Результат выполнения программы:



Чтение содержимого файлов

Для того, чтобы прочитать содержимое файла, мы должны сначала открыть этот файл в режиме чтения, затем создать входящий файловый поток, из которого мы будем считывать данные. В примере, приведенном ниже, мы считываем данные из файла C:\colours.txt . Файл содержит названия семи цветов, вот его содержимое:

Red
Green
Black
Yellow
Purple
Blue
White

Делаю локальный чат с функцией передачи файлов.
С отправкой текста проблем нету, но вот стабильно передавать файли не могу.

Сначала отправляем информацию о данных: mode (текст или файл), Temp (список юзеров кому отправлять), ну и имя и размер файла.
Потом отправляем файл по частям.

Смотрим что приходит нам ( текст или файл) ну и принимаем тоже блоками.
Проблема в том что клиент как мне кажется отправляет все нормально.
А вот сервер принимает только очень маленькие файлы меньше 5 кб. При файлах большего размера он то принимает только часть информации или же не принимает ее вообще.
Никак не могу понять в чем проблема. Помогите решить или может у кого-то есть рабочий пример кода для передачи файлов. __________________
Помощь в написании контрольных, курсовых и дипломных работ здесь

Передача данных через QTcpSocket
Ситуевина следующая. Пишу клиент-серверное приложение. Схема работы следующая: Клиент формирует.

Передача данных через qtcpsocket
Приветствую, интересует вопрос о передачи данных через qtcpsocket. Мы спокойной можем передавать.

передача файлов
Как можно передавать/принимать файлы, если в новой версии нет send/receive networkfile Это же.

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

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

Отправитель:

Принимающая сторона:

в заголовочном понадобятся:
QByteArray line;
QVector<QByteArray> dataVector;

Передача файлов
Нужна помощь Есть код, который передаёт выбранный файл на сервер и хочу сделать чтобы можно было с.


Передача файлов
Тема не совсем в том разделе(в профильном не отвечают), поэтому спрошу здесь. Можно ли скинуть ряд.

Передача файлов
Можно ли скинуть архив с фотками с компьютера на айфон? Добавлено через 1 час 6 минут Знает кто?

Сервер чата работает в одном потоке, т.к. целью статьи я ставил описание примера, наиболее просто и наглядно показывающего использование сокетов библиотеки Qt. В одной из следующих статей я возможно опишу многопоточный чат.

1. Шаблон проектирования Adapter

рис. 1 шаблон проектирования адаптер. Проблема

рис. 1 шаблон проектирования адаптер. Проблема

На рисунке 1 показана типичная ситуация, в которой может быть уместным применение адаптера. Есть некоторый код (Client), который использует экземпляры классов A и B, реализующих общий интерфейс (Interface). В один прекрасный момент, нам потребовалось наравне с A и B использовать класс Adaptee, но он не реализует нужный нам интерфейс.

Первый вариант решения такой проблемы заключается в наследовании классов Interface и Adaptee классом Adapter, как показано на рисунке 2. При этом в отношении класса Adaptee используется закрытое наследование, т.к. адаптер не должен предоставлять лишний интерфейс. Такой вариант решения проблемы называется адаптером классов, использует множественное наследование и все вытекающие из него проблемы.

рис. 2 адаптер классов

рис. 2 адаптер классов

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

рис. 3 адаптер объектов

рис. 3 адаптер объектов

2. Работа с сетью в Qt. Классы QTcpServer и QTcpSocket

Чтобы данные поступили в сокет, их нужно туда записать, для этого используется метод QTcpSocket::write. Мы можем олдскульно записывать в сокет последовательности байт:

В приведенном примере в сокет записывается столько байт, начиная с адреса переменной i, сколько достаточно для хранения целого числа. На другом конце провода можно будет считать эти байты методом read, но это очень не удобно, поэтому есть другое, более красивое решение с использованием QByteArray и QDataStream.

3. Пример использования паттерна Adapter

рис. 4 необычный адаптер

рис. 4 необычный адаптер

Хотелось бы, чтобы сокет сообщал о разрыве соединения и новых данных, когда они полностью получены, а также, позволял бы отправлять данные. Для этого интерфейс адаптера должен содержать 2 сигнала и метод (или слот) отправки. Такой интерфейс показан на листинг 3.

Класс адаптера агрегирует сокет и наследует интерфейс. В результате все операции сокета оказываются скрыты за приятным интерфейсом.

Пример был бы более удачным, если чат мог бы получать данные из других источников (помимо TCP-сокета), которые реализовывали бы наш интерфейс. В качестве таких источников могли бы быть например обертки над QUdpSocket или вариации на тему передачи данных в защищенном виде. Наш же пример адаптера по результатам применения получился похожим на фасад.

4. Исходный код сетевого чата

Диаграмма классов (не совсем UML) наших клиента и сервера приведена на рисунке 5. Часть классов мы уже подробно рассмотрели.

рис. 5 диаграмма классов сетевого чата

рис. 5 диаграмма классов сетевого чата

MainWidget представляет собой главное окно чата, он агрегирует форму, созданную в Qt Designer [4]. Форма содержит 2 поля ввода и кнопку. При щелчке на кнопку вызывается функция sendString класса ClientSocketAdapter, а поле ввода очищается. При получении сигнала message от ClientSocketAdapter, второе поле ввода главной формы дополняется принятой от сервера строкой.

Первое различие между ними заключается в том, что адаптер серверного сокета создается на основе уже имеющегося объекта QTcpSocket, а адаптер сокета клиента должен создать такой объект. Эта разница учтена в конструкторе класса SocketAdapter.

Кроме того, клиентский сокет должен выполнить метод connectToHost чтобы начать диалог с сервером. Сервер таких действий предпринимать не должен.

Полный исходный код клиента и сервера можно скачать бесплатно: клиент-серверный чат Qt.

В следующей статье мы подумаем над распараллеливанием сервера с использованием QThread.

Класс QFtp предназначен для создания клиентских приложений, работающих с протоколом FTP. Он реализует набор функций, для выполнения наиболее распространенных операций этого протокола, включая get(), put(), remove() и mkdir().

Все операции выполняются асинхронно. Когда вызывается функция, такая как get() или put(), управление сразу же возвращается программе, а собственно передача данных начинает производиться, когда управление опять переходит в цикл обработки событий Qt. Благодаря этому, во время исполнения FTP-команд, не возникает эффекта "замораживания" интерфейса с пользователем.

Демонстрацию возсможностей QFtp начнем с показа того, как скачать файл с сервера, используя функцию get(). Предположим, что основной класс приложения MainWindow должен скачать прейскурант с FTP-сайта.

Начинается функция с попытки открыть на запись файл в текущем каталоге. Затем выполняется последовательность из пяти FTP-команд. Второй аргумент функции get() задает устройство, в которое будет осуществляться запись принимаемых данных.

Команды FTP ставятся в очередь и исполняются в цикле обработки событий Qt. По завершении обработки всех команд, объект QFtp выдает сигнал done(bool), который подключен к слоту ftpDone(bool).

Класс QFtp предоставляет следующие операции: connectToHost(), login(), close(), list(), cd(), get(), put(), remove(), mkdir(), rmdir() и rename(). Все эти функции ставят соответствующие команды в очередь и возвращают идентификационный номер команды. Любые команды FTP могут быть испольнены с помощью функции rawCommand(). Например, так выглядит исполнение команды SITE CHMOD:

Объекты QFtp, перед исполнением команды, выдают сигнал commandStarted(int), а по завершении -- commandFinished(int, bool). Аргумент int -- это идентификационный номер команды. Если вас интересует ход выполнения отдельных команд, то вам придется сохранять их идентификационные номера, при вызове соответствующей функции. Благодаря этому появится возможность предоставить пользователю более детальную информацию о ходе процесса. Например: Другой способ обеспечения пользователя обратной связью с процессом -- использовать сигнал stateChanged().

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

При возникновении ошибки, QFtp автоматически очищает очередь команд. Это означает, что если ошибка произошла во время установления соединения или во время авторизации на сервере, следующие за ними команды никогда не будут выполнены. Но если после возникновения ошибки в очередь будут поставлены другие команды, то они будут исполнены как ни в чем не бывало.

Теперь рассмотрим более сложный пример:

Экземпляр класса Downloader попытается скачать все файлы из каталога FTP. Имя каталога задается как QUrl, при вызове конструктора. Класс QUrl -- это стандартный класс из библиотеки Qt, который реализует интерфейс для работы со строками URL и выделения их них отдельных частей, таких как имя файла, путь к файлу, протокол и порт. В конструкторе прежде всего выполняется проверка строки URL -- она должна начинаться с комбинации символов: "ftp:". Затем из URL извлекается номер порта, если порт не указан, то предполагается использование стандартного FTP-порта -- 21.

Затем выполняются соединения сигнал-слот и в очередь помещаются 4 FTP-команды. Последняя из них запрашивает у сервера список файлов и выдает сигнал listInfo(const QUrlInfo &), когда от сервера приходит очередное имя файла. Этот сигнал связан со слотом listInfo(), отвечающим за скачивание файла.

Аргумент типа QUrlInfo предоставляет подробную информацию о файле. Если это обычный файл (не каталог) и доступен на чтение, то производится попытка скачать его, вызовом get(). Объект QFile используется для сохранения локальной копии файла, он создается оператором new, а указатель на него сохраняется в динамическом массиве (векторе) openedFiles. Слот ftpDone() вызывается по завершении выполнения последовательности команд или в случае возникновения ошибки. Функция удаляет все объекты QFile, попутно закрывая все файлы. (Файлы закрываются автоматически деструктором класса QFile.)

Если ошибок не возникло, то порядок выполнения команд и выдачи сигналов будет следующим:

В обоих вышеприведенных примерах, файл скачивается с помощью функции get() и записывается на диск посредством объекта QFile. В случае же, если принятый файл нужно сохранить в памяти, то для этого прекрасно подойдет класс QBuffer, производный от класса QIODevice -- обертки вокруг класса QByteArray. Например:

В функции get() мы могли бы опустить второй аргумент или передать в место него "пустой" (NULL) указатель. В этом случае QFtp будет выдавать сигнал readyRead() всякий раз, при поступлении очередной порции данных, которые могут быть прочитаны вызовом readBlock() или readAll().

Если необходимо отображать ход выполнения скачивания файла, то можно связать сигнал dataTransferProgress(int, int), класса QFtp, со слотом setProgress(int, int) класса QProgressBar или QProgressDialog. Кроме того, можно привязать сигнал canceled(), класса QProgressBar или QProgressDialog со слотом abort(), класса QFtp.

Представьте, что вы с другом пишете реферат и у вас один учебник на двоих. Вы сели писать реферат, написали несколько страниц, оставили учебник открытым с намерением дописать его позже и ушли по своим делам. В это время ваш друг, который живет с вами в одной комнате, вернулся домой, увидел, что у вас что-то написано на листах, а рядом лежит учебник и решил, что вы закончили свой реферат. Он начинает листать учебник, выкидывая все ваши закладки, находит нужный ему материал и пишет свой реферат. Спустя несколько часов вы возвращаетесь домой, ваш друг уже спит, и вы решаете дописать реферат. Садитесь за письменный стол и «о, ужас!» все ваши закладки сбиты и вы не можете найти то место, где остановились. Неприятная ситуация? А ведь такая же может возникнуть в многопоточной среде, когда одни и те же внешние данные используются несколькими потоками. О том, как с этим жить, я расскажу в этой статье.

QtC++
QMutex
QSemaphore
QWaitCondition
std::mutex
std::semaphore
std::condition_variable

Применение этих сущностей я покажу на примерах и расскажу как они устроены и как их применять. Приведённый далее код будет написан на Qt, т. к. С++ код практически идентичен, есть лишь некоторые отличия между чистым С++ и Qt, и в таких случаях я приведу оба примера кода.

1. Проблема

Давайте перейдем к примерам и поставим задачу. Пусть имеется 2 банковских счета с 1000 рублей на каждом. Два пользователя одновременно инициируют операции перевода между ними: со счета №1 переводится 500 рублей на счет №2, а со счета №2 на счет №1 переводится 1200 рублей. Чтобы переводы выполнялись «одновременно», создадим объект выполняющий операцию перевода и его выполнение запустим в двух разных потоках.

Запускаем программу и получаем следующий результат:

Ну что, вас ничего не смущает? Как мы видим, выполнилась лишь первая операция — перевод 500 рублей с первого счета на второй, а перевести 1200 рублей со второго на первый не удалось, т. к. в момент начала операции на втором счете ещё не было нужной суммы. Давайте решать эту проблему.

2. Мьютексы (mutex)

В переводе с английского mutex (мьютекс) означает «взаимное исключение». Мьютекс гарантирует, что из всех потоков, которые попытались его захватить, будет запущен лишь один поток в одну единицу времени, а остальные будут отправлены в очередь ожидания.

Будьте осторожны с мьютексом. Его надо обязательно отпустить, иначе его нельзя будет захватить. Поскольку это частая ошибка и в больших проектах выявить её очень сложно, то были придуманы сущности для работы с мьютексами с использованием идиомы RAII (Resource Acquisition Is Initialization).

QtC++
QMutexLockerstd::lock_guard

RAII — идиома, смысл которой заключается в том, что получение ресурса совмещено с инициализацией объекта, а освобождение с уничтожением объекта. Таким образом, вместе с уничтожением объекта QMutexLocker автоматически вызывается unlock мьютекса, если требуется. Давайте применим эти сущности для исправления нашего кода с помощью мьютексов.

3. Семафоры (semaphore)

Семафоры, по сути своей, есть те же мьютексты, но с одним отличием. Семафор является счетным объектом, т. к. его можно выставить несколько раз и потом столько же раз его можно отпустить. Т.е. мьютекс является как бы бинарным — выставлен или нет, а семафор является счетчиком.

Для дальнейших примером давайте рассматривать следующую задачу. Первый поток — это работодатель, который каждую секунду в течение 12 секунд перечисляет в кошелек отцу 400 рублей. У отца есть сын Вася, который просит у отца на мороженное стоимостью 500 рублей. Если у отца достаточно денег, он выдает ему, если денег недостаточно, то и мороженного нет. Баланс кошелька мы можем хранить в семафоре. Тогда получим следующее решение:

и выводимый результат:

4. Переменные условия­ (Condition variables или Wait conditions)

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

QtC++
QWaitConditionstd::condition_vairable

Давайте также разберем на примере задачи про отца и мороженное, только теперь у отца будет два сына, содержимое кошелька будет снова определяться переменной типа int, а не семафором.

Обратите внимание, что в строке 54 мы вызываем метод notify_one(), который пробуждает один поток, поэтому лишь один сын сможет купить мороженное и отец может накапливать деньги.

Обращение к CV не является потокобезопасным, поэтому необходимо использовать мьютекс

Если же мы захотим порадовать мороженным обоих сыновей, при наличие такой возможности, то используем метод notify_all(). Для наглядного решения уменьшим зарплату отца до 900 рублей. Получим следующий результат:

Теперь в январе, июне и ноябре мороженное ест лишь один сын (к счастью для Васи и к несчастью для Пети).

В С++ CV предоставляют лаконичный интерфейс, позволяя совместить проверку условия и ожидание CV:

В метод wait, помимо мьютекста, передается предикат, который задает некоторое условие для пробуждения потока при получении сигнала от CV. Т.е. при получении уведомления от работодателя о перечислении денег, предикат проверит, хватает ли денег на мороженное, и если да, то только тогда выполнение потока будет продолжено, а иначе он снова уснет.

5. Другие способы

Вы не обязаны применять именно эти сущности, поэтому некоторые задачи можно решить и иначе. В задаче №3 можно вместо семафора применять мьютекс и периодически проверять переменную баланса, хватает ли денег.

Иногда может возникнуть задача, когда малое количество потоков или даже один изредка пишет в буфер, а множество потоков выполняют только доступ на чтение к этому буферу. Применение CV здесь не слишком эффективно, т. к. вы будете пробуждать все потоки (и записывающие и читающие) и самостоятельно реализовывать проверку возможности к действию. Мьютексы тоже не эффективны, если множество потоков постоянно осуществляют чтение блокируя доступ к буферу, то записывающий поток может ждать свою очередь очень долго. Или наоборот, множественная запись может парализовать чтение. Для таких ситуаций тоже существуют свои более эффективные сущности:

QtC++
QReadWriteLockstd::shared_mutex
QReadLocker
QWriteLocker
std::shared_lock
std::lock_guard

6. Выводы

В целом нет жестких рекомендаций о том, какие сущности где и как применять. Здесь вы вольны сами выбирать подходящий вам инструмент. Однако, не забывайте про то, что за всё приходится платить. Всегда задавайте себе вопрос, а как часто будет пробуждаться поток, как часто он будет работать, а не гоняю ли я его зря? А может есть более дешевый способ выполнить эту работу? Всё это так или иначе приходит с опытом. Пробуйте, практикуйтесь и исследуйте! Всего доброго!

Читайте также: