为什么我无法打开/读取从 Python 调用的 C 扩展名中的 txt 文件?
Why I'm unable to open/read txt file in C extension called from Python?
我尝试将文件名从python传递到C\C++ .dll并使C\C++代码打开/读取该文件。
这是一个非常简单的例子,说明我试图使用 ctypes 实现的目标。请原谅我的C++代码的菜鸟。我在这里学习。
//C++ code in example.cpp compiled to example.dll
#include <stdio.h>
extern "C" {
char* _line;
char* test(char* txt){
FILE* f_name;
f_name = fopen(txt, "r");
//... read data from file and do something
_line = txt;
return _line; // this is just my sanity check to see if "file.txt" got passed from python
}
}
我使用 cygwin-64 将其编译为.dll:
g++ -fPIC -shared example.cpp -o example.dll
Python 包装器:
import ctypes
print("works!") #just sanity check...
lib = ctypes.CDLL("example.dll")
cpp_file_access = lib.test
cpp_file_access.argtypes = [ctypes.c_char_p]
cpp_file_access.restype = ctypes.c_char_p
print(cpp_file_access(b"file.txt")) #sanity check to see if file name got passed
当从 python 调用 .dll 中的 test() 时,程序不会通过行:
f_name = fopen(txt, "r");
无论我使用哪种方法来打开/访问所述txt文件。它要么"挂起"而不执行任何操作,要么抛出指示访问冲突的 WindowsError 0x00000(...)。 当我在代码中使用任何类型的"打印"函数时,也会发生相同的行为C++例如:
printf("test print !");
std::cout << "another test print";
.dll代码在其他情况下可以正常工作,除非我尝试打开/读取 txt 文件或用从 python 调用的代码将某些内容"打印"到控制台C++。 实际上,当我将其编译为.exe文件时,它会打开/读取文件并将任何内容打印到控制台上都没有问题。
我找不到我的问题的任何解决方案/答案。 也许这里有人可以启发我做错了什么?
[编辑 #1] 我注意到了一些事情。 当我尝试在 Python3.8 中运行此代码时,我收到错误消息,指出文件:
cygwin1.dll
cygstdc++-6.dll
cyggcc_s-seh-1.dll
即使它们位于Cygwin的bin文件夹中并且环境路径设置正确,也无法找到。我不得不将这些文件复制粘贴到示例.dll和python包装器(wrapper.py)所在的文件夹中。 我不知道这是否与我的问题有关,但我认为值得一提。我开始对那个cygwin编译器产生怀疑。挖掘仍在继续。
[编辑 #2] 我通过添加 void test_2() 修改了C++代码,因此在 python 和 .dll 之间没有传递参数。
__declspec(dllexport) void test_2(){
FILE* f_name;
f_name = fopen("file.txt", "r");
}
并从python调用它:
void_acc = lib.test_2
void_acc.restype = None
void_acc()
print ("program ended, go away !") // .. sanity check
问题保持不变。程序执行在到达 fopen() 行时停止。
两件事一目了然:
- 您必须确保在函数声明之前使用 __declspec(dllexport) 导出函数,或者将其包含在 def 文件中。 (如果你正在到达fopen线,这不是问题 - 只是为了完整性而提及。
- 您在 Python 中指定了一个宽 c 字符串指针 (c_wchar_t),但在 c 中声明了窄 c 字符串 (char*),这些需要匹配。
.argtypes
和.restype
不正确。 C 代码使用char*
所以使用c_char_p
:
import ctypes
lib = ctypes.CDLL("example.dll")
cpp_file_access = lib.test
cpp_file_access.argtypes = ctypes.c_char_p,
cpp_file_access.restype = ctypes.c_char_p
print(cpp_file_access(b'file.txt')) # pass byte string
请注意,不需要将参数包装在ctypes
类型中。ctypes
已经从.argtypes
知道该类型,如果您不传递与声明类型兼容的 Python 类型,则会抱怨。
解决了。
毕竟这是编译器问题。 与其使用cygwin,我应该使用mingw-64位。
https://www.msys2.org/
我按照这个 yt 视频中的说明进行操作: https://www.youtube.com/watch?v=aXF4A5UeSeM
工作正常。
如果由于某种原因yt链接已关闭,或者您不想看视频,我将发布该viodeo的步骤以进行保管。
转到: https://www.msys2.org/并单击下载安装程序的按钮。就我而言,它是(将来可能会有所不同):
msys2-x86_64-20200602.exe
安装它。记住你在哪里安装它。这将在几分钟内派上用场。 安装后,启动它(或选择在安装完成后自动启动)。将出现命令行窗口。在该命令行窗口中写入/pasete:
pacman -Syu --disable-download-timeout
等待它完成。之后关闭窗口。 转到您选择的安装文件夹。启动msys2.exe
.将出现命令行窗口。再次写入或粘贴:
pacman -Syu --disable-download-timeout
。并等待它完成。使命令行窗口保持打开状态。之后我们将使用它。 完成后,转到初始网页:https://www.msys2.org/并向下滚动,然后转到"浏览:包列表"。 在左侧转到"搜索"。 将"Search in"
归档设置为"base packages"
并在搜索框中键入"gcc"
。选择:
mingw-w64-gcc
然后,从"binary packages"
列表中选择:
mingw-w64-x86_64-gcc
查找"Installation"
标记(它应该位于页面的顶部)。那里有一个命令。将其复制/粘贴到终端:
pacman -S mingw-w64-x86_64-gcc --disable-download-timeout
(添加了"--disable-download-timeout"
) 等待它安装。使命令行窗口保持打开状态。2件事要去。 在命令行窗口中,重新粘贴上一个命令,但将最后一个字母从"gcc"
更改为"gdb"
或使用以下命令:
pacman -S mingw-w64-x86_64-gdb --disable-download-timeout
等待它安装。使命令行窗口保持打开状态。1件事要去。 在命令行窗口中,重新粘贴上一个命令,但将最后一个字母从"gdb"
更改为"make"
或使用以下命令:
pacman -S mingw-w64-x86_64-make --disable-download-timeout
等待它安装。我们已经完成了安装东西。但是,还有一个步骤 - 系统路径变量。 转到安装msys2-x86_64-20200602.exe
的文件夹,应该有一个"msys2.exe"
文件和一个"mingw64"
文件夹。转到该文件夹。查找"bin"
文件夹,复制其路径。 转到系统变量。 右键单击您的计算机图标。转到高级系统设置。转到环境变量(在底部)。查找名为"path"的变量,对其进行编辑。把";"在最后,如果它不存在,一切都准备好了。将<rest of the path>/mingw64/bin
文件夹路径粘贴在末尾的";"。
现在您可以在终端中使用 g++ 命令,例如:
g++ -fPIC -shared example.cpp -o example.dll
(用于制作.dll文件)。大功告成。
- C++中的VLA,扩展名为std=C++11
- 如何按文件扩展名引用文件夹中的文件
- VSCode 中带有 C/C++ 扩展名的多行注释缩进错误
- 为什么我无法打开/读取从 Python 调用的 C 扩展名中的 txt 文件?
- 使用Boost文件系统C++将具有特定扩展名的文件的名称保存在特定文件夹中
- 共享库 (.so) 没有扩展名的 Linux 可执行文件之间的区别?
- Visual Studio Code "variable " u8 的 C/C++ 扩展名 " " 不是类型名称"
- Makefile by ocaml 和 cpp 扩展名
- CMake 不编译具有非标准扩展名的文件
- Visual Studio 2019 - 设置文件类型的默认扩展名
- 如何在 Windows 上获取带有 c++ 且没有 <dirent.h> 的特定扩展名的所有文件的列表
- 谁能告诉我,程序中的错误是什么?该程序仅用于获取文件扩展名
- 如何在 vscode 扩展名中检索 C/C++ 文件的编译命令
- 通过cMake使用具有自定义文件扩展名的共享库
- 如何在 CMake 中"override"文件的按扩展名类型
- 在另一个字符串中插入文件扩展名之前的字符串
- 在 Python 3.6 中调用C++扩展时导入错误"undefined symbol: _ZNK9FastNoise8GetNoiseEff"
- 如何在不使用文件扩展名的情况下使用命令行参数打开C++中的文本文件?
- 如何调用 ShellExecute 以使用 C++ 打开具有特定程序的文件,而无需关联相同的文件扩展名
- 针对不同的文件扩展名调用不同的函数