【问题标题】:peculiar error on ntpath.pyntpath.py 上的特殊错误
【发布时间】:2013-12-27 01:18:34
【问题描述】:

我正在尝试在 Windows 7 上的 vlc 播放器上编写类似的包装器,以便它可以通过按键加载文件夹中的下一个和上一个文件。我在其中所做的是,我将文件路径作为参数创建 vlc 类的实例并使用 pyHook,扫描键,当检测到特定击键时调用实例上的 play_next 和 play_prev 方法。这些方法通过杀死最后一个进程并使用 get_new_file 方法找到的下一个文件生成新的 vlc 来工作。它在前几次有效,然后给出了特殊的错误。

None   
None   
Traceback (most recent call last):  
  File "C:\Python27\pyHook\HookManager.py", line 351, in KeyboardSwitch   
    return func(event)   
  File "filestuff.py", line 64, in kbwrap   
    kbeventhandler(event,instance)   
  File "filestuff.py", line 11, in kbeventhandler   
    instance.play_prev()   
  File "filestuff.py", line 34, in play_prev   
    f=self.get_new_file(-1)   
  File "filestuff.py", line 40, in get_new_file   
    dirname= os.path.dirname(self.fn)   
  File "C:\Python27\lib\ntpath.py", line 205, in dirname   
    return split(p)[0]   
  File "C:\Python27\lib\ntpath.py", line 178, in split   
    while head2 and head2[-1] in '/\\':   
TypeError: an integer is required

代码如下:

import os
import sys
import pythoncom, pyHook 
import win32api
import subprocess
import ctypes

def kbeventhandler(event,instance):

    if event.Key=='Home':
        instance.play_prev()
    if event.Key=='End':
        instance.play_next()
    return True

class vlc(object):
    def __init__(self,filepath,vlcp):
        self.fn=filepath
        self.vlcpath=vlcp
        self.process = subprocess.Popen([self.vlcpath, self.fn])
    def kill(self):
        PROCESS_TERMINATE = 1
        handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, self.process.pid)
        ctypes.windll.kernel32.TerminateProcess(handle, -1)
        ctypes.windll.kernel32.CloseHandle(handle)
        print self.process.poll()
    def play_next(self):
        self.kill()
        f=self.get_new_file(1)
        self.process = subprocess.Popen([self.vlcpath, f])
        self.fn=f
    def play_prev(self):
        self.kill()
        f=self.get_new_file(-1)
        self.process = subprocess.Popen([self.vlcpath, f])
        self.fn=f

    def get_new_file(self,switch):

        dirname= os.path.dirname(self.fn)    
        supplist=['.mkv','.flv','.avi','.mpg','.wmv']
        files = [os.path.join(dirname,f) for f in os.listdir(dirname) if (os.path.isfile(os.path.join(dirname,f)) and os.path.splitext(f)[-1]in supplist)]
        files.sort()
        try: currentindex=files.index(self.fn)
        except: currentindex=0
        i=0
        if switch==1:
            if currentindex<(len(files)-1):i=currentindex+1

        else:
            if currentindex>0:i=currentindex-1

        return files[i]    

def main():
    vlcpath='vlc'
    if os.name=='nt': vlcpath='C:/Program Files (x86)/VideoLAN/VLC/vlc.exe'
    fn='H:\\Anime\\needless\\Needless_[E-D]\\[Exiled-Destiny]_Needless_Ep11v2_(04B16479).mkv'
    if len(sys.argv)>1:
        fn=sys.argv[1] #use argument if available or else use default file
    instance=vlc(fn,vlcpath)
    hm = pyHook.HookManager()
    def kbwrap(event):
        kbeventhandler(event,instance)
    hm.KeyDown = kbwrap
    hm.HookKeyboard()    
    pythoncom.PumpMessages()

if __name__ == '__main__':
    main() 

这里也是:http://pastebin.com/rh82XGzd

【问题讨论】:

  • def kill(self): self.process.terminate()
  • 尝试将close_fds=True 传递给Popen(不会有问题)。
  • 如果你删除pyHook的东西并循环调用play_next()play_prev()会发生什么?
  • kill() 的代码是为了避免:“第一次终止后无法访问。”不要在一行中使用多个语句(由于 cmets 的格式限制,我使用了它)。我认为如果您删除 pyHook 代码,那么错误就会消失。尝试在play_prev/next 中设置一个标志,仅此而已。并在另一个读取此标志的线程中启动/停止 vlc。这个想法是避免从事件处理程序中启动子流程。
  • def kbwrap(event): return kbeventhandler(event,flag) #

标签: python windows-7 path subprocess


【解决方案1】:

问题是 在main 中我设置了hm.KeyDown = kbwrap,然后从函数kbwrap 调用了实际的事件处理程序kbeventhandler,但没有从kbwrap 返回任何值

def kbwrap(event):
    return kbeventhandler(event,flag)
hm.KeyDown = kbwrap

而且我还将 vlc 工作卸载到另一个线程,因为 pyHook 与子进程不兼容。 最终工作代码:

import os
import sys
import pythoncom, pyHook 
import win32api
import subprocess
import ctypes
import threading
from multiprocessing import *

class vlcThread(threading.Thread):
    def __init__(self,filepath,vlcp,fl):
        threading.Thread.__init__(self)
        self.fn,self.vlcpath,self.flag=filepath,vlcp,fl
        self.daemon=True

        self.start() # invoke the run method

    def run(self):
        vlcinstance=vlc(self.fn,self.vlcpath)
        while True:
            if(self.flag.value==1):
                vlcinstance.play_next()
                self.flag.value=0
            if(self.flag.value==-1):
                vlcinstance.play_prev()
                self.flag.value=0







def kbeventhandler(event,flag):

    if event.Key=='Home':
        flag.value =-1
        return False
    if event.Key=='End':
        flag.value =1
        return False
    return True

class vlc(object):
    def __init__(self,filepath,vlcp):
        self.fn=filepath
        self.vlcpath=vlcp
        self.process = subprocess.Popen([self.vlcpath,self.fn],close_fds=True)
    def kill(self):
        p, self.process = self.process, None
        if p is not None and p.poll() is None:
            p.kill() 
            p.wait()


    def play_next(self):
        self.kill()
        f=self.get_new_file(1)
        self.process = subprocess.Popen([self.vlcpath,f],close_fds=True)
        self.fn=f
    def play_prev(self):
        self.kill()
        f=self.get_new_file(-1)
        self.process = subprocess.Popen([self.vlcpath, f],close_fds=True)
        self.fn=f

    def get_new_file(self,switch):

        dirname= os.path.dirname(self.fn)    
        supplist=['.mkv','.flv','.avi','.mpg','.wmv','ogm','mp4']
        files = [os.path.join(dirname,f) for f in os.listdir(dirname) if (os.path.isfile(os.path.join(dirname,f)) and os.path.splitext(f)[-1]in supplist)]
        files.sort()
        try: currentindex=files.index(self.fn)
        except: currentindex=0
        i=0
        if switch==1:
            if currentindex<(len(files)-1):i=currentindex+1

        else:
            if currentindex>0:i=currentindex-1

        return files[i]    



def main():
    vlcpath='vlc'
    flag=Value('i')
    flag.value=0
    if os.name=='nt': vlcpath='C:/Program Files (x86)/VideoLAN/VLC/vlc.exe'
    fn='H:\\Anime\\needless\\Needless_[E-D]\\[Exiled-Destiny]_Needless_Ep11v2_(04B16479).mkv'
    if len(sys.argv)>1:
        fn=sys.argv[1] #use argument if available or else use default file

    t=vlcThread(fn,vlcpath,flag)
    hm = pyHook.HookManager()
    def kbwrap(event):
        return kbeventhandler(event,flag)
    hm.KeyDown = kbwrap
    hm.HookKeyboard()    
    pythoncom.PumpMessages()


if __name__ == '__main__':
    main() 

【讨论】:

  • 不要在 REPL 或 __init__.py 之外使用 from x import *。您可以将 r'' 字符串文字用于 Windows 路径,例如 r'C:\Program Files (x86)\VideoLAN\VLC\vlc.exe'flag 这个词暗示了 True/False(开/关)(这只是我对调试的建议)。 Using Queue 将避免繁忙的循环。引入restart(newfilename)方法避免代码重复。在__init__ 中设置self.process=None 并调用.restart(filepath),即应从单个方法调用Popen()
  • 你可以使用collections.deque()来实现get_next_file()get_prev_file()。然后def play_next(self): self.restart(self.get_next_file())def play_prev(self): self.restart(self.get_prev_file())
猜你喜欢
  • 1970-01-01
  • 2011-03-03
  • 2012-02-23
  • 1970-01-01
  • 2011-07-20
  • 1970-01-01
  • 2022-10-16
  • 1970-01-01
相关资源
最近更新 更多