Simple problem, I just can't open/create a file. It's supposed to save some settings in an xml-file to a given path.
I call the method like this:
xmlwriter->write_settings("./settings.xml");
int XmlWriter::write_settings(QString path)
{
qDebug() << "Path is: " + path;
QDomDocument document;
QDomElement root = document.createElement("settings");
document.appendChild(root);
QDomElement node;
node.setAttribute("name", "Its me!");
node.setAttribute("series", "25");
node.setAttribute("PMT", "200");
root.appendChild(node);
QFile file(path);
if(!file.open(QIODevice::ReadWrite, QIODevice::Text))
{
qDebug() << "Opening file failed!";
return 1;
}
else
{
QTextStream stream(&file);
stream << document.toString();
file.close();
qDebug() << "wrote file to " + path;
return 0;
}
}
You don't pass parameters correctly, so you probably invoke a polymorphic version of QFile::open
Try this:
QFile file(path);
if(!file.open(QIODevice::ReadWrite | QIODevice::Text))
{
qDebug() << "Opening file failed!";
return 1;
}
else
{
QTextStream stream(&file);
stream << document.toString();
file.close();
qDebug() << "wrote file to " + path;
return 0;
}
Related
I am using 7za.exe as subprocess to unzip the files with qt and cpp. I used a checkbox to include the option of recursive unzipping, the recursive option does not seem to work here. Could anyone suggest where I am doing wrong?
void MainWindow::uncompressZipFile()
{
QStringList queryArguments;
queryArguments << "e";
queryArguments << """" + choosenDir + """"+"/*.zip";
if(ui->checkBox->isChecked())
queryArguments << "-ro"+choosenDir+"/example";
queryArguments << "-o"+choosenDir+"/example";
QFileInfoList dirs;
QFileInfoList files;
for(int i=0; i < dirs.size(); i++)
{
qDebug() << "Directories listed here";
qDebug() << dirs.at(i);
}
QDirIterator it(choosenDir, QStringList() << "*.zip", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()){
qDebug() << it.next();
ui->resultList->addItem(it.next());
}
zipperProcess.setWorkingDirectory(QCoreApplication::applicationDirPath());
qDebug() << zipperProcess.workingDirectory();
qDebug()<<queryArguments;
zipperProcess.start("7za.exe", queryArguments);
}
I tried to block multiple file at once, then copy them to another location.
Both source and destination files should be blocked simultaneously. Therefore I can't use static QFile::copy() function.
To hold and move files I use QSharedPointer< QFile > due to QFile is neither copyable nor moveable.
To perform whole the operation entirely I use QtConcurrent framework. Namely: QtConcurrent::mappedReduced and QFutureWatcher.
To open all pairs of files I use map functor, then to sequentially copy them I use reduce functor.
using PFile = QSharedPointer< QFile >;
using PFileList = QList< PFile >;
template< typename Result, typename Functor >
struct FunctorWithResultType
: std::decay_t< Functor >
{
using result_type = Result;
FunctorWithResultType(Functor & functor)
: std::decay_t< Functor >{std::forward< Functor >(functor)}
{ ; }
};
template< typename Result, typename Functor >
FunctorWithResultType< Result, Functor >
addResultType(Functor && functor)
{
return {functor};
}
class Test
{
public :
QDir currentDirectory;
QFutureWatcher< PFileList > fileCopyFutureWatcher;
// ...
};
// ...
Test::Test()
{
auto onFilesCopied = [&]
{
PFileList copiedFiles = fileCopyFutureWatcher.result();
qCInfo(usbDevice) << "Files copy operation from drive finished.";
qCInfo(usbDevice) << copiedFiles.size();
for (PFile const & file : copiedFiles) {
//file->close(); // I want copiedFiles to be closed automatically at the end of current scope
}
};
connect(&fileCopyFutureWatcher, &fileCopyFutureWatcher.finished, onFilesCopied);
}
// ...
void Test::onDeviceAdded(QString deviceName)
{
qCInfo(usbDevice) << "USB device" << deviceName << "is added.";
if (!fileCopyFutureWatcher.isFinished()) {
return;
}
QDir sourceDirectory{deviceName};
if (!sourceDirectory.cd("dir")) {
qCInfo(usbDevice) << "Drive" << deviceName << "does not contain dir subdirectory.";
return;
}
auto destinationDirectory = currentDirectory;
if (!destinationDirectory.mkpath("fileCache")) {
qCCritical(usbDevice) << "Can't create fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
if (!destinationDirectory.cd("fileCache")) {
qCCritical(usbDevice) << "Can't change directory to fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
struct PFilePair
{
PFile source, destination;
};
auto openSourceAndDestinationFiles = [&, destinationDirectory] (QFileInfo const & fileInfo) -> PFilePair
{
auto source = PFile::create(fileInfo.absoluteFilePath());
QFile & sourceFile = *source;
if (!sourceFile.open(QFile::ReadOnly)) {
qCCritical(usbDevice) << "Can't open file" << sourceFile.fileName()
<< "to read:" << sourceFile.errorString();
return {};
}
auto destination = PFile::create(destinationDirectory.absoluteFilePath(fileInfo.fileName()));
QFile & destinationFile = *destination;;
if (!destinationFile.open(QFile::ReadWrite | QFile::Truncate)) {
qCCritical(usbDevice) << "Can't open file" << destinationFile.fileName()
<< "to write:" << destinationFile.errorString();
return {};
}
return {qMove(source), qMove(destination)};
};
auto copyFiles = [&] (PFileList & files, PFilePair const & filePair)
{
if (filePair.source.isNull() || filePair.destination.isNull()) {
return;
}
QFile & sourceFile = *filePair.source;
QFile & destinationFile = *filePair.destination;
qCInfo(usbDevice) << sourceFile.fileName() << "->" << destinationFile.fileName();
constexpr int size = (1 << 20); // 1MiB
QByteArray buffer{size, 0};
char * const data = buffer.data();
while (!sourceFile.atEnd()) {
auto bytesRead = sourceFile.read(data, size);
if (bytesRead < 0) {
qCCritical(usbDevice) << "Can't read file" << sourceFile.fileName()
<< ":" << sourceFile.errorString();
return;
}
auto bytesWritten = destinationFile.write(data, bytesRead);
while (bytesWritten < bytesRead) {
auto sizeWritten = destinationFile.write(data + bytesWritten, bytesRead - bytesWritten);
if (sizeWritten < 0) {
qCCritical(usbDevice) << "Can't write file" << destinationFile.fileName()
<< ":" << destinationFile.errorString();
return;
}
bytesWritten += sizeWritten;
}
Q_ASSERT(bytesWritten == bytesRead);
}
Q_ASSERT(sourceFile.size() == destinationFile.size());
destinationFile.flush();
files.append(filePair.destination);
};
QStringList nameFilters;
nameFilters << "file.dat";
// many other entries
auto entryInfoList = sourceDirectory.entryInfoList(nameFilters, (QDir::Readable | QDir::Files));
fileCopyFutureWatcher.setFuture(QtConcurrent::mappedReduced< PFileList >(qMove(entryInfoList), addResultType< PFilePair >(openSourceAndDestinationFiles), copyFiles));
}
// ...
After reading result in QFutureWatcher::finished event all the destination files are still opened and blocked by my application. Therefore I can conclude that copies of QSharedPointer< QFile > are still exists. I suspect that they leave in QFuture inside QFutureWatcher. How can I clear all of them (i.e. how to cause QFile::~QFile() to close all files) without calling QFutureWatcher::setFuture with fake QFuture instance?
To achieve this I need to steal result from QFuture, not to copy.
My workaround looks like following:
using PFile = QSharedPointer< QFile >;
using PFileList = QList< PFile >;
template< typename Result, typename Functor >
struct FunctorWithResultType
: std::decay_t< Functor >
{
using result_type = Result;
FunctorWithResultType(Functor & functor)
: std::decay_t< Functor >{std::forward< Functor >(functor)}
{ ; }
};
template< typename Result, typename Functor >
FunctorWithResultType< Result, Functor >
addResultType(Functor && functor)
{
return {functor};
}
class Test
{
public :
QDir currentDirectory;
// ...
};
// ...
void Test::onDeviceAdded(QString deviceName)
{
qCInfo(usbDevice) << "USB device" << deviceName << "is added.";
QDir sourceDirectory{deviceName};
if (!sourceDirectory.cd("dir")) {
qCInfo(usbDevice) << "Drive" << deviceName << "does not contain dir subdirectory.";
return;
}
auto destinationDirectory = currentDirectory;
if (!destinationDirectory.mkpath("fileCache")) {
qCCritical(usbDevice) << "Can't create fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
if (!destinationDirectory.cd("fileCache")) {
qCCritical(usbDevice) << "Can't change directory to fileCache subdirectory in"
<< destinationDirectory.absolutePath()
<< "directory";
return;
}
struct PFilePair
{
PFile source, destination;
};
auto openSourceAndDestinationFiles = [&, destinationDirectory] (QFileInfo const & fileInfo) -> PFilePair
{
auto source = PFile::create(fileInfo.absoluteFilePath());
QFile & sourceFile = *source;
if (!sourceFile.open(QFile::ReadOnly)) {
qCCritical(usbDevice) << "Can't open file" << sourceFile.fileName()
<< "to read:" << sourceFile.errorString();
return {};
}
auto destination = PFile::create(destinationDirectory.absoluteFilePath(fileInfo.fileName()));
QFile & destinationFile = *destination;;
if (!destinationFile.open(QFile::ReadWrite | QFile::Truncate)) {
qCCritical(usbDevice) << "Can't open file" << destinationFile.fileName()
<< "to write:" << destinationFile.errorString();
return {};
}
return {qMove(source), qMove(destination)};
};
auto copyFiles = [&] (PFileList & files, PFilePair const & filePair)
{
if (filePair.source.isNull() || filePair.destination.isNull()) {
return;
}
QFile & sourceFile = *filePair.source;
QFile & destinationFile = *filePair.destination;
qCInfo(usbDevice) << sourceFile.fileName() << "->" << destinationFile.fileName();
constexpr int size = (1 << 20); // 1MiB
QByteArray buffer{size, 0};
char * const data = buffer.data();
while (!sourceFile.atEnd()) {
auto bytesRead = sourceFile.read(data, size);
if (bytesRead < 0) {
qCCritical(usbDevice) << "Can't read file" << sourceFile.fileName()
<< ":" << sourceFile.errorString();
return;
}
auto bytesWritten = destinationFile.write(data, bytesRead);
while (bytesWritten < bytesRead) {
auto sizeWritten = destinationFile.write(data + bytesWritten, bytesRead - bytesWritten);
if (sizeWritten < 0) {
qCCritical(usbDevice) << "Can't write file" << destinationFile.fileName()
<< ":" << destinationFile.errorString();
return;
}
bytesWritten += sizeWritten;
}
Q_ASSERT(bytesWritten == bytesRead);
}
Q_ASSERT(sourceFile.size() == destinationFile.size());
destinationFile.flush();
files.append(filePair.destination);
};
auto & fileCopyFutureWatcher = *new QFutureWatcher< PFileList >{this};
auto onFilesCopied = [&]
{
fileCopyFutureWatcher.deleteLater();
PFileList copiedFiles = fileCopyFutureWatcher.result();
qCInfo(usbDevice) << "Files copy operation from drive finished.";
qCInfo(usbDevice) << copiedFiles.size();
for (PFile const & file : copiedFiles) {
// ...
}
};
connect(&fileCopyFutureWatcher, &fileCopyFutureWatcher.finished, onFilesCopied);
QStringList nameFilters;
nameFilters << "*.dat";
auto entryInfoList = sourceDirectory.entryInfoList(nameFilters, (QDir::Readable | QDir::Files));
fileCopyFutureWatcher.setFuture(QtConcurrent::mappedReduced< PFileList >(qMove(entryInfoList), addResultType< PFilePair >(openSourceAndDestinationFiles), copyFiles));
}
// ...
I almost sure, that fileCopyFutureWatcher instance will be deleted reliably.
I have to copy the files from a source directory to a destination directory. Could you please provide the code for doing such operation
I wanted something similar, and was googling (in vain), so this is where I've got to:
static bool cpDir(const QString &srcPath, const QString &dstPath)
{
rmDir(dstPath);
QDir parentDstDir(QFileInfo(dstPath).path());
if (!parentDstDir.mkdir(QFileInfo(dstPath).fileName()))
return false;
QDir srcDir(srcPath);
foreach(const QFileInfo &info, srcDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
QString srcItemPath = srcPath + "/" + info.fileName();
QString dstItemPath = dstPath + "/" + info.fileName();
if (info.isDir()) {
if (!cpDir(srcItemPath, dstItemPath)) {
return false;
}
} else if (info.isFile()) {
if (!QFile::copy(srcItemPath, dstItemPath)) {
return false;
}
} else {
qDebug() << "Unhandled item" << info.filePath() << "in cpDir";
}
}
return true;
}
Recently I programmed to do file transmission with Qt. Thought it worked now, I'm still curious about what happened. Please help me find out the reason. Many thanks.
Why the size of head is bigger than the sum of sizeof(qin32), sizeof(qint32) and length of file name?(I guess it is the reason of function - setVersion())
QFileInfo info(file_to_send.fileName());
QByteArray head;
QDataStream out(&head, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << qint32(file_to_send.size() + info.fileName().length() + sizeof(qint32)*2)
<< qint32(info.fileName().length())
<< info.fileName();
tcpClient.write(head);
You have made it to complicated. Pattern is like that:
QFileInfo info(file_to_send.fileName());
QByteArray head;
QDataStream out(&head, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << qint32(0)
<< info.fileName(); // << YouCanAddMoreStuffHere;
out.device()->seek(0);
out << qint32(out.length());
tcpClient.write(head);
and read code:
void SomeClass::slotReadClient() { // slot connected to readyRead signal of QTcpSocket
QTcpSocket *tcpSocket = (QTcpSocket*)sender();
QDataStream clientReadStream(tcpSocket);
while(true) {
if (!next_block_size) {
if (tcpSocket->bytesAvailable() < sizeof(qint32)) { // are size data available
break;
}
clientReadStream >> next_block_size;
}
if (tcpSocket->bytesAvailable() < next_block_size) {
break;
}
QString fileName;
clientReadStream >> fileName; // >> YouCanAddMoreStuffHere; // same as above
next_block_size = 0;
}
}
info.filename() writes out its own length
if you don't want that then you can do
QFileInfo info(file_to_send.fileName());
QByteArray head;
QDataStream out(&head, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
QByteArray filename = info.fileName().toLatin1();
out << qint32(file_to_send.size() + filename .length() + sizeof(qint32)*2);
<< qint32(filename .length())
out.writeRawData(fileName.constData(), filename.length());
tcpClient.write(head);
using writeRawData which bypasses any built in encoding
I am writing a class to parse Itunes Libray File using QXmlQuery and QT-XSLT.
Here's my sample code:
ItunesLibParser::ItunesLibParser()
{
pathToLib = QString("/Users/rakesh/temp/itunes_xslt/itunes_music_library.xml");
}
void ItunesLibParser::createXSLFile(QFile &inFile)
{
if (inFile.exists()) {
inFile.remove();
}
inFile.open(QIODevice::WriteOnly);
QTextStream out(&inFile);
out << QString("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
out << QString("<xsl:stylesheet version=\"2.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">");
out << QString("<xsl:output method=\"text\" />");
out << QString("<xsl:template name=\"playlistNames\">");
out << QString("<xsl:value-of select=\"child::integer[preceding-sibling::key[1]='Playlist ID']\"/>");
out << QString("<xsl:text>
</xsl:text>");
out << QString("<xsl:value-of select=\"child::string[preceding-sibling::key[1]='Name']\"/>");
out << QString("<xsl:text>
</xsl:text>");
out << QString("</xsl:template>");
out << QString("<xsl:template match=\"/\">");
out << QString("<xsl:for-each select=\"plist/dict/array/dict\">");
out << QString("<xsl:call-template name=\"playlistNames\"/>");
out << QString("</xsl:for-each>");
out << QString("</xsl:template>");
out << QString("</xsl:stylesheet>");
inFile.close();
return;
}
void ItunesLibParser::dumpPlayList()
{
QXmlQuery query(QXmlQuery::XSLT20);
query.setFocus(QUrl(pathToLib));
QFile xslFile("plist.xsl");
createXSLFile(xslFile);
query.setQuery(QUrl("plist.xsl"));
QStringList* outDump = new QStringList();
query.evaluateTo(outDump);
if(outDump != NULL) {
QStringList::iterator iter = (*outDump).begin();
for (; iter != (*outDump).end();
++iter)
//code flow doesn't come here. It means being() == end()
std::cout << (*iter).toLocal8Bit().constData() << std::endl;
}
return;
}
OutDump here doesn't contain data. While in Shell (xmlpatterns-4.7 mystlye.xsl itunes_music_library.xml ), If I run my Query I get proper output.
Is there anything, wrong I am doing while calling it programatically? I checked out plist.xsl is created properly, but my doubt is whether "/Users/rakesh/temp/itunes_xslt/itunes_music_library.xml" this is getting loaded or not? Or there might be another reasons, I am confused. Is there any experts to throw some light onto problem, I will be glad.
Intead from reading from the file, I read the file into buffer and converted that int string as passed to setquery. That solved the problem.
Here's sample code for those who could face similar problem in future.
void ITunesMlibParser::parsePlayListItemXml(int plistId)
{
QXmlQuery xQuery(QXmlQuery::XSLT20);
QFile inFile("/Users/rakesh/temp/itunes_xslt/itunes_music_library.xml");
if (!inFile.open(QIODevice::ReadOnly)) {
return;
}
QByteArray bArray;
while (!inFile.atEnd()) {
bArray += inFile.readLine();
}
QBuffer xOriginalContent(&bArray);
xOriginalContent.open(QBuffer::ReadWrite);
xOriginalContent.reset();
if (xQuery.setFocus(&xOriginalContent))
std::cout << "File Loaded" << std::endl;
//..
//..
}
Thanks
Rakesh