使用 PyInstaller 创建 Python 可执行文件后权限被拒绝
Permission denied after using PyInstaller to create Python executable
我使用 Bottle 框架创建了一个小型网络服务器来提供一个网页。这是由我的 python 脚本 "hello.py" 完成的。从 "hello.py" 生成的网页中,我可以编辑名为 "data.txt" 的文件的内容。当我从我的终端 (python hello.py) 运行 "hello.py" 时,这一切都工作得很好。
但是当我使用 PyInstaller 创建可执行文件时,我 运行 遇到了问题。
我无法写入我的 "data.txt" 文件。我收到的错误消息是 "Permission denied"。可执行文件中的其他所有东西都可以工作,除了这个!
在创建我的可执行文件之前,我将 "data.txt" 权限设置为 777。这没有帮助。我还尝试了在这里找到的潜在解决方案 - 但没有成功。它看起来像这样:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
def fix_ownership(path):
"""Change the owner of the file to SUDO_UID"""
uid = os.environ.get('SUDO_UID')
gid = os.environ.get('SUDO_GID')
if uid is not None:
os.chown(resource_path(path), int(uid), int(gid))
@post('/data<dataValue>') # or @route('/login')
def data(dataValue):
thePostRequest = str(request.query_string)
newPostRequest = string.replace(thePostRequest, '%22', '\"')
fix_ownership("data.txt")
with open("data.txt","w") as fo:
fo.write('data = '+newPostRequest)
return
我寄予厚望,但这也没有奏效。这是我现在的代码(我是 Python 的新手所以让我知道任何明显的错误):
from bottle import route, run, static_file, get, post, request, response, redirect
import os
import string
import sys
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
@get('/Count<deviceNumber>') # or @route('/login')
def Count(deviceNumber):
return
def fix_ownership(path):
"""Change the owner of the file to SUDO_UID"""
uid = os.environ.get('SUDO_UID')
gid = os.environ.get('SUDO_GID')
if uid is not None:
os.chown(resource_path(path), int(uid), int(gid))
@post('/data<dataValue>') # or @route('/login')
def data(dataValue):
thePostRequest = str(request.query_string)
newPostRequest = string.replace(thePostRequest, '%22', '\"')
newPostRequest = newPostRequest.replace('%27', '\'')
# THIS DOES NOT WORK AFTER EXECUTABLE IS CREATED BY PYINSTALLER - PERMISSION DENIED :(
with open("data.txt","w") as fo:
fo.write('data = '+newPostRequest)
return
@get('/ajax<noCache>') # or @route('/login')
def ajax(noCache):
return
@get('/<filename:re:.*\.(jpg|png|gif|ico)>')
def send_image(filename):
print "getting image..."
return static_file(filename, root=resource_path('./'))
@get('/<filename:path>')
def send_static(filename):
return static_file(filename, root=resource_path('./'))
# return static_file(filename, root=os.path.join(sys._MEIPASS, './'))
@route('/formSubmit', method='POST')
def formSubmit():
redirect("/hello", 303)
return
@route('/hello')
@route('/hello', method='GET')
def hello():
return '''
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-->
<script type="text/javascript" src="data.txt"></script>
<script type="text/javascript" src="myJavascript.js"></script>
<link rel="stylesheet" type="text/css" href="style.css"></script>
<title>CANARI JR. | Home</title>
</head>
<body onload="preparePage()">
<div id="spinner"></div>
<div id="container">
<div id="headerDiv">
<div id="logoDiv"><a href="/" onclick="showHome(); return false;">
<img src="cLogo.png" alt="Canari Jr. Logo">
</a>
</div>
<div id="navDiv">
<a href="/" onclick="showHome(); return false;"><p id="homeBtn" style="color:black;background-color:white">Home</p></a>
<a href="/" onclick="showSetup(); return false;"><p id="settingsBtn">Settings</p></a>
</div>
</div>
<div id="contentDiv">
</div>
<div id="addDiv" style="text-align:center;display:none;">
<h2>Add New Device</h2>
<form method="POST" id="deviceForm" action="/formSubmit" onsubmit="writeTxt('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P');">
<p style="background-color:#f5f5f5;" id="deviceDropdown">Monitor Type:<select name="" id="deviceList" onchange="loadContentA(this.value)">
<option value="default">Choose one...</option>
<option value="temp">Temperature</option>
<option value="humidity">Humidity</option>
<option value="analog">Analog</option>
<option value="digital">Digital</option>
<option value="counter">Counter</option>
</select></p>
<div id="clearDiv" style="clear:both"></div>
<a href="/" id="cancelBtn" onclick="hideAddDiv(); return false;">Cancel</a>
</form>
</div>
<div id="editDiv" style="display:none">
</div>
<div id="setupDiv" style="display:none">
<h2 style="margin-bottom:35px; border:3px solid #8C8C8C; width:40%; margin:0 auto; padding:10px">Change IP Address</h2>
<form method="POST" onsubmit="submitIP('ipAddress'); return false;">
<p>New IP Address: <input type="text" name="ipAddress" id="ipAddress"><input type="submit" value="Submit" style="padding:5px 10px 5px 10px">
</p>
<p>Make sure to <span style="color:red">write down this IP Address</span> as you will need it to complete setup.</p><br>
</form>
<h2 style="margin-bottom:35px; border:3px solid #8C8C8C; width:40%; margin:0 auto; padding:10px;margin-top:45px;">Binding Mode</h2>
<p>Binding Mode is currently:</p>
<a href="/" id="bindBtn" onclick="bindOn(); return false;" class="btn">OFF</a>
<p>(Click to change)</p>
</div>
</div>
</body>
</html>
'''
run(host='0.0.0.0', port=8080, debug=True)
我正在使用 Mac OSX。
我想通了!首先,我必须使用此函数引用我的 "data.txt" 文件:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
我是这样用的:
theDataFile = resource_path('./data.txt')
然后当我去写我的文件时,它成功了!像这样:
def data(dataValue):
thePostRequest = str(request.query_string)
newPostRequest = string.replace(thePostRequest, '%22', '\"')
newPostRequest = newPostRequest.replace('%27', '\'')
newPostRequest = newPostRequest.replace('%20', ' ')
newPostRequest = newPostRequest.replace('%7B', '{')
newPostRequest = newPostRequest.replace('%7D', '}')
print "This is the data value: " + newPostRequest
theDataFile = resource_path('./data.txt')
with open(theDataFile,"w") as fo:
fo.write('data = '+newPostRequest)
return
我使用 Bottle 框架创建了一个小型网络服务器来提供一个网页。这是由我的 python 脚本 "hello.py" 完成的。从 "hello.py" 生成的网页中,我可以编辑名为 "data.txt" 的文件的内容。当我从我的终端 (python hello.py) 运行 "hello.py" 时,这一切都工作得很好。
但是当我使用 PyInstaller 创建可执行文件时,我 运行 遇到了问题。 我无法写入我的 "data.txt" 文件。我收到的错误消息是 "Permission denied"。可执行文件中的其他所有东西都可以工作,除了这个!
在创建我的可执行文件之前,我将 "data.txt" 权限设置为 777。这没有帮助。我还尝试了在这里找到的潜在解决方案 - 但没有成功。它看起来像这样:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
def fix_ownership(path):
"""Change the owner of the file to SUDO_UID"""
uid = os.environ.get('SUDO_UID')
gid = os.environ.get('SUDO_GID')
if uid is not None:
os.chown(resource_path(path), int(uid), int(gid))
@post('/data<dataValue>') # or @route('/login')
def data(dataValue):
thePostRequest = str(request.query_string)
newPostRequest = string.replace(thePostRequest, '%22', '\"')
fix_ownership("data.txt")
with open("data.txt","w") as fo:
fo.write('data = '+newPostRequest)
return
我寄予厚望,但这也没有奏效。这是我现在的代码(我是 Python 的新手所以让我知道任何明显的错误):
from bottle import route, run, static_file, get, post, request, response, redirect
import os
import string
import sys
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
@get('/Count<deviceNumber>') # or @route('/login')
def Count(deviceNumber):
return
def fix_ownership(path):
"""Change the owner of the file to SUDO_UID"""
uid = os.environ.get('SUDO_UID')
gid = os.environ.get('SUDO_GID')
if uid is not None:
os.chown(resource_path(path), int(uid), int(gid))
@post('/data<dataValue>') # or @route('/login')
def data(dataValue):
thePostRequest = str(request.query_string)
newPostRequest = string.replace(thePostRequest, '%22', '\"')
newPostRequest = newPostRequest.replace('%27', '\'')
# THIS DOES NOT WORK AFTER EXECUTABLE IS CREATED BY PYINSTALLER - PERMISSION DENIED :(
with open("data.txt","w") as fo:
fo.write('data = '+newPostRequest)
return
@get('/ajax<noCache>') # or @route('/login')
def ajax(noCache):
return
@get('/<filename:re:.*\.(jpg|png|gif|ico)>')
def send_image(filename):
print "getting image..."
return static_file(filename, root=resource_path('./'))
@get('/<filename:path>')
def send_static(filename):
return static_file(filename, root=resource_path('./'))
# return static_file(filename, root=os.path.join(sys._MEIPASS, './'))
@route('/formSubmit', method='POST')
def formSubmit():
redirect("/hello", 303)
return
@route('/hello')
@route('/hello', method='GET')
def hello():
return '''
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-->
<script type="text/javascript" src="data.txt"></script>
<script type="text/javascript" src="myJavascript.js"></script>
<link rel="stylesheet" type="text/css" href="style.css"></script>
<title>CANARI JR. | Home</title>
</head>
<body onload="preparePage()">
<div id="spinner"></div>
<div id="container">
<div id="headerDiv">
<div id="logoDiv"><a href="/" onclick="showHome(); return false;">
<img src="cLogo.png" alt="Canari Jr. Logo">
</a>
</div>
<div id="navDiv">
<a href="/" onclick="showHome(); return false;"><p id="homeBtn" style="color:black;background-color:white">Home</p></a>
<a href="/" onclick="showSetup(); return false;"><p id="settingsBtn">Settings</p></a>
</div>
</div>
<div id="contentDiv">
</div>
<div id="addDiv" style="text-align:center;display:none;">
<h2>Add New Device</h2>
<form method="POST" id="deviceForm" action="/formSubmit" onsubmit="writeTxt('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P');">
<p style="background-color:#f5f5f5;" id="deviceDropdown">Monitor Type:<select name="" id="deviceList" onchange="loadContentA(this.value)">
<option value="default">Choose one...</option>
<option value="temp">Temperature</option>
<option value="humidity">Humidity</option>
<option value="analog">Analog</option>
<option value="digital">Digital</option>
<option value="counter">Counter</option>
</select></p>
<div id="clearDiv" style="clear:both"></div>
<a href="/" id="cancelBtn" onclick="hideAddDiv(); return false;">Cancel</a>
</form>
</div>
<div id="editDiv" style="display:none">
</div>
<div id="setupDiv" style="display:none">
<h2 style="margin-bottom:35px; border:3px solid #8C8C8C; width:40%; margin:0 auto; padding:10px">Change IP Address</h2>
<form method="POST" onsubmit="submitIP('ipAddress'); return false;">
<p>New IP Address: <input type="text" name="ipAddress" id="ipAddress"><input type="submit" value="Submit" style="padding:5px 10px 5px 10px">
</p>
<p>Make sure to <span style="color:red">write down this IP Address</span> as you will need it to complete setup.</p><br>
</form>
<h2 style="margin-bottom:35px; border:3px solid #8C8C8C; width:40%; margin:0 auto; padding:10px;margin-top:45px;">Binding Mode</h2>
<p>Binding Mode is currently:</p>
<a href="/" id="bindBtn" onclick="bindOn(); return false;" class="btn">OFF</a>
<p>(Click to change)</p>
</div>
</div>
</body>
</html>
'''
run(host='0.0.0.0', port=8080, debug=True)
我正在使用 Mac OSX。
我想通了!首先,我必须使用此函数引用我的 "data.txt" 文件:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
我是这样用的:
theDataFile = resource_path('./data.txt')
然后当我去写我的文件时,它成功了!像这样:
def data(dataValue):
thePostRequest = str(request.query_string)
newPostRequest = string.replace(thePostRequest, '%22', '\"')
newPostRequest = newPostRequest.replace('%27', '\'')
newPostRequest = newPostRequest.replace('%20', ' ')
newPostRequest = newPostRequest.replace('%7B', '{')
newPostRequest = newPostRequest.replace('%7D', '}')
print "This is the data value: " + newPostRequest
theDataFile = resource_path('./data.txt')
with open(theDataFile,"w") as fo:
fo.write('data = '+newPostRequest)
return