Пытаюсь удалить файл с помощью python, но получаю ошибку разрешения WinError 32 - PullRequest
0 голосов
/ 21 марта 2019

Итак, у меня есть довольно странная проблема, которую было действительно трудно воспроизвести. Я играю звуки с несколькими различными библиотеками в зависимости от типа файла. Я хочу иметь возможность удалить звук, поэтому я очищаю аудиоплеер (переназначая переменную audio_player) перед удалением файла с помощью os.remove (), именно тогда я получаю ошибку разрешения, но только когда очищенный аудиоплеер был используя pygame. Я понятия не имел, почему это происходит, но я смог последовательно воспроизвести его в тестовом файле, вот и этот файл, и исходный файл. Он имеет отношение к SoundPlayer.reload_sound_from_different_file ()

Original aka AudioPlayer

import pygame
import MetaData
import os
import time
from random import random
from PyQt5.QtCore import pyqtSignal, QObject, QRunnable, pyqtSlot


class PlaysoundException(Exception):
    pass


class SoundSigs(QObject):
    time_changed = pyqtSignal()
    set_current_time = pyqtSignal(float)
    reset_cursor = pyqtSignal()
    error = pyqtSignal(str)


class SoundPlayer(QRunnable):
    def __init__(self):
        super(SoundPlayer, self).__init__()
        self.path = ''
        self.signals = SoundSigs()
        self.wav_list = ['.wav']
        self.pygame_list = ['.flac', '.ogg', '.mp3']
        self.current_result = ''
        self.pixel_time_conversion_rate = 0
        self.audio_player = AudioPlayer()

    def reset(self):
        self.audio_player.stop()
        self.audio_player = AudioPlayerPlaceholder()

    def space_bar(self):
        if self.audio_player.ended:
            self.audio_player.goto(0)
        elif self.audio_player.playing:
            self.audio_player.pause()
        else:
            self.audio_player.resume()

    @pyqtSlot()
    def run(self):
        while True:
            while self.audio_player.playing and not self.audio_player.ended and not \
                    self.audio_player.passed_download_head:
                time.sleep(.003)
                self.signals.time_changed.emit()
            time.sleep(.01)

    def load(self, path, pixel_time_conversion_rate):
        self.pixel_time_conversion_rate = pixel_time_conversion_rate
        self.audio_player = self.get_correct_audio_player(path)
        self.audio_player.load(path)

    def get_correct_audio_player(self, path):
        file_type = os.path.splitext(path)[1].lower()
        if file_type in self.wav_list:
            return WavPlayer()
        elif file_type in self.pygame_list:
            return PygamePlayer()

    def load_segment(self, path, true_duration, pixel_time_conversion_rate):
        current_time = self.audio_player.current_time
        playing = self.audio_player.playing
        self.audio_player.stop()
        self.audio_player = self.get_correct_audio_player(path)
        self.pixel_time_conversion_rate = pixel_time_conversion_rate
        self.audio_player.load_segment(path, true_duration)
        self.audio_player.goto(current_time)
        if playing:
            self.audio_player.play()

    def preload(self, true_duration, pixel_time_conversion_rate):
        self.audio_player.stop()
        self.signals.time_changed.emit()
        self.audio_player = AudioPlayerPlaceholder()
        self.pixel_time_conversion_rate = pixel_time_conversion_rate
        self.audio_player.preload(true_duration)
        self.audio_player.play()

    def reload_sound_from_different_file(self, path):
        current_time = self.audio_player.current_time
        playing = self.audio_player.playing
        self.audio_player.stop()
        self.audio_player = self.get_correct_audio_player(path)
        self.audio_player.load(path)
        self.audio_player.goto(current_time)
        if playing:
            self.audio_player.play()

    @staticmethod
    def calculate_px_time_conversion_rate(waveform_width, sound_duration):
        return waveform_width/sound_duration

    def goto(self, position):
        self.audio_player.goto(position/self.pixel_time_conversion_rate)
        self.signals.time_changed.emit()


class AudioPlayerSigs(QObject):
    error = pyqtSignal(str)


class AudioPlayer:
    def __init__(self):
        self.signals = AudioPlayerSigs()
        self.loaded = False
        self._playing = False
        self.loop = False
        self.segment = False
        self._path = ''
        self.path = ''
        self._original_path = ''
        self._meta_data = None
        self._duration = 0
        self.attempted_current_time = 0
        self.passed_download_head = False
        self._current_time_start = 0
        self.current_time_stop = 0
        self._current_time_stop = 0
        self._current_time = 0
        self.current_time = 0

    def __del__(self):
        self._meta_data = None

    @property
    def current_time_stop(self):
        if not self.playing:
            return self._current_time_stop
        return time.time()

    @current_time_stop.setter
    def current_time_stop(self, value):
        self._current_time_stop = value

    @property
    def playing(self):
        return self._playing

    @playing.setter
    def playing(self, value):
        if value:
            self._current_time_start = time.time()
        else:
            self._current_time = self.current_time
            self.current_time_stop = time.time()
            self._current_time_start = time.time()
        self._playing = value

    @property
    def path(self):
        return self._path

    @path.setter
    def path(self, value):
        self._original_path = value
        self._path = get_short_path_name(value)

    @property
    def current_time(self) -> int:
        if self.playing:
            return int((self.current_time_stop - self._current_time_start)*1000) + self._current_time
        return self._current_time

    @current_time.setter
    def current_time(self, value):
        self._current_time_start = time.time()
        self._current_time = value

    @property
    def meta_data(self):
        if self.loaded:
            return self._meta_data
        self._meta_data = self.get_meta_file()
        return self._meta_data

    @property
    def true_duration(self):
        return self.meta_data['duration']

    @property
    def duration(self):
        if self.segment:
            return self._duration
        return self.true_duration

    @property
    def ended(self):
        return self.duration <= self.current_time

    def get_meta_file(self):
        return MetaData.get_meta_file(self._original_path)

    def load(self, path):
        self.path = path

        self._meta_data = self.get_meta_file()
        self.loaded = True
        self._load(self.path)

    def _load(self, path):
        pass

    def reload(self, path, playing):
        self.path = path
        self._meta_data = self.get_meta_file()
        self.stop()
        self._reload(path)
        self.loaded = True
        if playing:
            self.play()

    def _reload(self, path):
        pass

    def play(self):
        if not self.playing:
            self.playing = True
            self._play()

    def _play(self):
        pass

    def pause(self):
        if self.playing:
            self.playing = False
            self._pause()

    def _pause(self):
        pass

    def resume(self):
        if not self.playing:
            self.playing = True
            self._resume()

    def _resume(self):
        pass

    def stop(self):
        if self.loaded:
            self._reset()
            self._stop()

    def _stop(self):
        pass

    def goto(self, position):
        self.current_time = position
        if self.segment and position >= self.true_duration:
            self.pause()
            self.attempted_current_time = position
            self.passed_download_head = True
        else:
            self._goto(position)
        if not self.playing:
            self._pause()

    def _goto(self, position):
        pass

    def _reset(self):
        self.loaded = False
        self.playing = False
        self.loop = False
        self.segment = False
        self.passed_download_head = False
        self.current_time = 0

    def end(self):
        if self.loop:
            self.goto(0)
            self.play()

    def swap_file_with_complete_file(self, path):
        if self.passed_download_head:
            current_time = self.attempted_current_time
        else:
            current_time = self.current_time
        playing = self.playing
        self.stop()
        self.reload(path, playing)
        self.goto(current_time)

    load_rest_of_segment = swap_file_with_complete_file

    def swap_file_with_incomplete_file(self, path, duration):
        current_time = self.current_time
        self.stop()
        self.load_segment(path, duration)
        self.goto(current_time)
        self.play()

    def load_segment(self, path, duration):
        self.segment = True
        self._duration = duration
        self.load(path)


class WavPlayer(AudioPlayer):
    def __init__(self):
        super(WavPlayer, self).__init__()
        self.alias = ''

    def __del__(self):
        self.win_command('close', self.alias)

    def _load(self, path):
        self.alias = 'playsound_' + str(random())
        self.win_command('open "' + self.path + '" alias', self.alias)
        self.win_command('set', self.alias, 'time format milliseconds')

    def _reload(self, path):
        self._load(path)

    def _play(self):
        self.win_command('play', self.alias, 'from', str(round(self.current_time)), 'to', str(self.duration))

    def _pause(self):
        self.win_command('pause', self.alias)

    def _resume(self):
        self.win_command('play', self.alias)

    def _stop(self):
        self.win_command('stop', self.alias)

    def _goto(self, position):
        self.win_command('play', self.alias, 'from', str(round(position)), 'to', str(self.duration))

    @staticmethod
    def win_command(*command):
        from ctypes import c_buffer, windll
        from sys import getfilesystemencoding
        buf = c_buffer(255)
        command = ' '.join(command).encode(getfilesystemencoding())
        errorCode = int(windll.winmm.mciSendStringA(command, buf, 254, 0))
        if errorCode:
            errorBuffer = c_buffer(255)
            windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
            exceptionMessage = ('\n    Error ' + str(errorCode) + ' for command:'
                                                                  '\n        ' + command.decode() +
                                '\n    ' + errorBuffer.value.decode())
            raise PlaysoundException(exceptionMessage)
        return buf.value


class PygamePlayer(AudioPlayer):
    def __init__(self):
        super(PygamePlayer, self).__init__()
        pygame.mixer.pre_init(48000, -16, 2, 1024)

    def __del__(self):
        pygame.mixer.quit()
        self.path = None
        print('deleted')

    def _load(self, path):
        frequency = int(self.meta_data['sample rate'])
        channels = int(self.meta_data['channels'])
        pygame.mixer.quit()
        pygame.mixer.init(frequency=frequency, channels=channels)
        try:
            pygame.mixer.music.load(path)
        except pygame.error:
            self.signals.error.emit("Couldn't play this file!  It may be that it's corrupted.  "
                                    "Try downloading it again.")

    def _reload(self, path):
        try:
            pygame.mixer.music.load(self.path)
        except pygame.error:
            self.signals.error.emit("Couldn't play this file!  It may be that it's corrupted.  "
                                    "Try downloading it again.")

    def _play(self):
        try:
            pygame.mixer.music.play()
        except Exception as e:
            self.signals.error.emit(e)

    def _pause(self):
        pygame.mixer.music.pause()

    def _resume(self):
        pygame.mixer.music.unpause()

    def _stop(self):
        pygame.mixer.music.stop()

    def _goto(self, position):
        try:
            self._reload(self.path)
            pygame.mixer.music.play(start=round(position)/1000)
        except pygame.error:
            pygame.mixer.music.set_pos(position)


class AudioPlayerPlaceholder(AudioPlayer):
    def __init__(self):
        super(AudioPlayerPlaceholder, self).__init__()
        self.passed_download_head = True

    @property
    def current_time(self):
        return self._current_time

    @current_time.setter
    def current_time(self, value):
        self._current_time = value

    @property
    def ended(self):
        return False

    def goto(self, position):
        self.current_time = position

    def preload(self, duration):
        self._duration = duration
        self.current_time = 0


def get_short_path_name(long_name):
    from ctypes import wintypes
    import ctypes
    _GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW
    _GetShortPathNameW.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD]
    _GetShortPathNameW.restype = wintypes.DWORD
    """
    Gets the short path name of a given long path.
    http://stackoverflow.com/a/23598461/200291
    """
    output_buf_size = 0
    while True:
        output_buf = ctypes.create_unicode_buffer(output_buf_size)
        needed = _GetShortPathNameW(long_name, output_buf, output_buf_size)
        if output_buf_size >= needed:
            return output_buf.value
        else:
            output_buf_size = needed

Тестовый файл

from AudioPlayer import SoundPlayer
import time
import os

file_name = "<file path>"
player = SoundPlayer()
player.load(file_name, 1)
player.audio_player.play()
time.sleep(5)
player.reload_sound_from_different_file(file_name)
time.sleep(2)
player.audio_player.stop()
player.reset()
time.sleep(1)
os.remove(file_name)

Я знаю, это довольно много, чтобы спросить, но я застрял на этом, как 3 дня, лол. Любая помощь будет принята с благодарностью!

Ответы [ 3 ]

0 голосов
/ 22 марта 2019

Каким-то образом установленные вами пакеты не могут быть помечены как доверенные приложения, это единственное, что я хотел бы попробовать, кроме предоставления администратору приложения временного доступа, щелкнув его правой кнопкой мыши и выбрав команду «Запуск от имени администратора».

Чтобы разблокировать пакеты, перейдите к /python/lib/ и найдите пакеты, которые ВЫ установили (если таковые имеются) или ПАКЕТЫ, указанные в программе.Щелкните правой кнопкой мыши по всем файлам Python, и, в зависимости от обстоятельств, может появиться окно с надписью «Разблокировать эту программу». Если это так, установите флажок и нажмите «Применить», затем «ОК».Я рекомендую делать это для каждого файла в пакете, который вы используете.

Если это не сработает (что с большой вероятностью не сработает, поскольку это необычная ошибка), просто скажите мне.

0 голосов
/ 23 марта 2019

Хорошо, я понял это! Проблема в том, что Pygame действительно не нравится, когда вы выходите из микшера более одного раза. У меня он выходил каждый раз, когда я инициализировал новый плеер, по какой-то причине он не выпустил файл полностью во второй раз. В итоге я сначала загрузил файл в память, а затем передал его в pygame, затем я мог удалить его на досуге:)

0 голосов
/ 21 марта 2019

У меня была похожая проблема с безопасностью Windows в приложении на работе несколько недель назад. В итоге я решил вызвать сценарии из командного файла с командной строкой, настроенной для администратора. Если вы хотите попробовать, создайте файл .bat с:

cd path/to/your/script
python myscript.py

Затем создайте ярлык для командного файла и на вкладке properties выберите advanced, затем run as administrator. Это приведет к запуску всех ваших сценариев с правами администратора при каждом двойном щелчке файла, и мне удастся избежать этих ошибок в моем случае. Это может сработать и для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...