【问题标题】:C++ char* relative file path? (Qt)C++ char* 相对文件路径? (Qt)
【发布时间】:2016-01-28 05:02:21
【问题描述】:

我正在尝试在可执行文件中播放 .mod 音频文件。我正在使用第 3 方 BASSMOD .dll。当我提供文件的完整路径时,我可以播放音频文件,但在提供相对路径时无法播放。这里有一些sn-ps。

main.cpp

#include <QCoreApplication>
#include "bassmod.h"

// define file location
const char* file = "C:/Users/Downloads/test4/console/music.mod";

void startMusic() {
  BASSMOD_Init(-1, 44100, 0);
  BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);
  BASSMOD_MusicPlayEx(0,-1,TRUE);
}

int main(int argc, char *argv[])
{
  QCoreApplication a(argc, argv);
  startMusic();
  return a.exec();
}

bassmod.h(相关sn-p)

BOOL BASSDEF(BASSMOD_MusicLoad)(BOOL mem, void* file, DWORD offset, DWORD length, DWORD flags);

我关心的函数是BASSMOD_MusicLoad。就这个项目而言,.mod 文件播放没有问题。但是,当我尝试将 .mod 文件的绝对路径更改为相对路径(“music.mod”)时,该文件无法播放。这是为什么?我的 .mod 文件与可执行文件位于同一目录以及包含 .pro 文件的目录中——这似乎不是问题。

另外,也许我遗漏了一些与如何在 C++ 中打开文件有关的内容。看起来MusicLoad 函数要求第二个参数是void* 类型。我敢肯定有很多不同的事情我可以在这里做得更好。理想情况下,我希望能够让file 存储.mod 文件的相对路径并让它以这种方式播放,这样我就不必硬编码绝对路径。在一个完美的世界中,我想在我的 resources.qrc 中为file 提供一个指向 .mod 文件的路径,但是我相信我必须使用QFile,因为我需要类型为 void*。

对初学者的任何帮助将不胜感激。


EDIT 01:感谢大家的帮助!我让它工作(至少使用相对文件路径)。有两种方法可以做到这一点。以下是我所做的以及我如何测试它:

第一种情况假设 BASSMOD(或您正在使用的任何外部 dll)不处理相对路径。

const char* file = "C:/debug/music.mod"; // same dir as .exe
QFileInfo info("music.mod");
QString path = info.absoluteFilePath();
const string& tmp = path.toStdString();
const char* raw = tmp.data();

这些是我设置的测试项目。当我运行BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS); 时,它按预期工作。那是我对完整的绝对路径进行硬编码的时候。

当我运行BASSMOD_MusicLoad(FALSE,(void*)raw,0,0,BASS_MUSIC_RAMPS); 时,它不起作用。所以我决定打印出所有东西的值,看看哪里出了问题:

 cout << "Qstring path: ";
 qDebug() << path;
 cout << "string& tmp: ";
 cout << tmp << endl;
 cout << "raw: ";
 cout << raw << endl;
 cout << "full char* file: ";
 cout << file;
 startMusic();

...返回这个:

Qstring path:
"C:/myApp/build-Debug/music.mod"
string& tmp:
C:/myApp/build-Debug/music.mod
raw:
C:/myApp/build-Debug/music.mod
full char* file:
C:/myApp/build-Debug/debug/music.mod

注意区别?当我硬编码文件的完整路径时,我发现(感谢@FrankOsterfeld 和@JasonC)当前工作目录实际上不是 .exe (/debug) 或 .pro 文件所在的位置。它实际上与 Makefile 位于同一目录中。

所以我把它改成这样:QFileInfo info("./debug/x.m"); 并且它起作用了。

尽管问题最终是我不知道当前工作目录在哪里,@Radek、@SaZ 和 @JasonC 的解决方案帮助找到了解决这个问题的另一种方法(另外它向我展示了如何让工作目录和类型之间的转换)。对于想要使用 QFileInfo 来确定您在文件系统中的实际位置的人来说,这是一个很好的参考。如果我使用的 dll 不能很好地处理相对路径,我会使用这个解决方案。不过……

我想知道是否可以将相同的解决方案应用于我的原始代码(不使用 QFileInfo 和转换类型等)。我假设 BASSMOD 没有处理开箱即用的相对路径。我错了。我将 file 变量更改为 const char* file = "./debug/x.m"; 它有效!

谢谢大家的帮助!

但是,我仍然希望使用来自 Qt 资源文件的 music.mod 来使其正常工作。不过,根据回复,除非您使用的第 3 方库支持 Qt 资源系统,否则这似乎是不可能的。

【问题讨论】:

  • BASSMOD_MusicLoad 返回什么错误码?
  • 要做到这一点,我可以将cout &lt;&lt; BASSMOD_ErrorGetCode(); 放在BASSMOD_MusicLoad 行下吗?当我这样做时,它只会将“2”返回到标准输出。编辑:没关系。我在头文件中找到了错误代码。 “2”是#define BASS_ERROR_FILEOPEN 2 // can't open the file
  • 所以它显然只是找不到文件。我想这与 BASSMOD 如何读取文件有关。由于它是一个编译后的 .dll,不幸的是,它有点像黑盒。
  • 我不想问这个显而易见的问题,但只是为了解决这个问题,您的文件还存在吗?您是否可能在实验中不小心移动/重命名/删除了它?您确定您的“music.mod”拼写正确(没有逗号代替句点、其他常见的拼写错误等)吗?
  • 您确定 BASSMOD_MusicLoad 是否考虑了当前工作目录? (您可以检查它的路径,例如 QDir::homePath)。

标签: c++ qt bass


【解决方案1】:

我的 .mod 文件与可执行文件位于同一目录中。

在 Qt Creator 中,默认的初始工作目录是 .pro 文件所在的目录,而不是 .exe 最终所在的目录。

要么将你的文件放在那个目录中(如果你使用典型的设置,这个目录可能包含所有源文件等),或者将启动目录更改为 .exe 文件所在的目录(在运行设置区域)。

虽然,根据您在下面的新评论,我想问题比这更深...我无法真正告诉您为什么 BASS 不喜欢相对文件名,但您可以将相对路径转换为绝对路径将其传递给 BASS。有很多方法可以做到这一点;使用 Qt 的 API,您可以:

#include <QFileInfo>

...
const char* file = "music.mod";  // Your relative path.
...

BASSMOD_MusicLoad(...,
                  (void*)QFileInfo(file).absoluteFilePath().toAscii().data(),
                  ...);

在一个完美的世界中,我想在我的 resources.qrc 中提供带有 .mod 文件路径的文件

您将无法这样做,因为从 .qrc 文件加载资源是 Qt 的事情,而 BASS 可能不会在内部使用 Qt(就像您无法使用 fopen 打开资源一样),并且不会不了解如何加载 Qt 嵌入的资源。我对 BASS 不熟悉,但粗略地看一下 this documentation 表明它还具有从内存缓冲区播放数据的能力。因此,一种方法是使用 Qt 将资源加载到可访问的内存中并传递该缓冲区。

【讨论】:

  • 忘了提到我把文件放在我能找到的任何地方,只是想看看这是否是问题所在。依然没有。即使我将文件放在与 .pro 文件相同的目录中。不过,这仍然是一个很好的提示。
  • 我可能会查看内存缓冲区选项。唯一的问题是,当我出于某种原因这样做时,程序会启动防病毒软件,这是我绝对不希望发生的事情。
  • @orbit 查看编辑,我想将其转换为绝对路径可能会起作用,尽管它并没有真正解决它首先导致问题的原因。
  • char *abspath = ... - 您正在保存指向临时值的指针。这是内存损坏。请修正你的答案。
  • @SaZ 谢谢;你去吧。我试图让它更具可读性,但计划适得其反。
【解决方案2】:

在一个完美的世界中,我想在我的 resources.qrc 中提供带有 .mod 文件路径的文件,但是我相信我必须使用 QFile,因为我需要类型无效*。

为什么你只相信?阅读 Qt 文档。它会起作用的。不要使用 QFile 类,而是使用 QFileInfo

QFileInfo info(:/resourcePrefix/name);
QString path = info.absoluteFilePath();
void* rawPtr = (void*)path.toStdString().c_str();

【讨论】:

  • void* rawPtr = (void*)path.toStdString().c_str(); - 此指针在下一行代码中将无效,因为 path.toStdString() 是右值。不要这样做。
  • 下一个错误:你不能在Qt库之外使用像:/resourcePrefix/name这样的qt资源路径,因为你不确定BASS是否支持Qt资源系统。我相信它没有。
  • @SaZ 到第一条评论:它将工作直到代码到达块的末尾,然后字符串从内存中释放(我同意 toStdString() 创建一个副本)并变得无效。直到该用户必须使用 BASSMOD_MusicLoad 加载数据。
  • @SaZ 到第二条评论:您可能是对的,BASSMOD_MusicLoad 不会找到必须加载的字节的正确位置。在图书馆不支持它可能是问题。 (也许最糟糕的解决方案是在运行时将文件从资源复制到临时目录,而不是播放它)
  • @Radek SaZ 关于.c_str() 的结果是正确的。 .toStdString() 返回的 std::string 实质上消失在该行的下一个分号处,并连同其 .c_str() 工作缓冲区一起消失。
猜你喜欢
  • 1970-01-01
  • 2014-07-22
  • 2015-04-13
  • 1970-01-01
  • 2016-10-05
  • 2017-04-21
  • 1970-01-01
  • 2014-09-26
  • 1970-01-01
相关资源
最近更新 更多