Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 我想要一个索引文件目录的聪明算法…指针?_Python_Mysql_Sql_Database_Hash - Fatal编程技术网

Python 我想要一个索引文件目录的聪明算法…指针?

Python 我想要一个索引文件目录的聪明算法…指针?,python,mysql,sql,database,hash,Python,Mysql,Sql,Database,Hash,我在Ubuntu(.mp3、.wav等)文件中有一个音乐目录。这个目录可以有它需要的任意多个子目录,没有限制。我希望能够从中创建一个音乐库,即基于以下过滤器返回歌曲列表: 1) 播放列表的成员资格 2) 艺人名称 3) 字符串搜索 4) 歌名 等等等等 但是,如果文件名被更改、移动,甚至添加到我的音乐目录中,我需要能够在我的音乐组织引擎中反映这一点-快速 我最初想用pyinotify、incron或inotify监视我的目录。不幸的是,我的目录是一个Samba共享,因此监视文件事件。所以我的下一

我在Ubuntu(.mp3、.wav等)文件中有一个音乐目录。这个目录可以有它需要的任意多个子目录,没有限制。我希望能够从中创建一个音乐库,即基于以下过滤器返回歌曲列表:

1) 播放列表的成员资格 2) 艺人名称 3) 字符串搜索 4) 歌名 等等等等

但是,如果文件名被更改、移动,甚至添加到我的音乐目录中,我需要能够在我的音乐组织引擎中反映这一点-快速

我最初想用pyinotify、incron或inotify监视我的目录。不幸的是,我的目录是一个Samba共享,因此监视文件事件。所以我的下一个猜测是简单地用python递归搜索目录,并填充SQL数据库。然后在更新时,我会查看是否有任何更改(扫描每个子文件夹,查看每个歌曲的名称是否已经在数据库中,如果没有添加),并相应地进行更新。不幸的是,这似乎是一个糟糕的
O(n^2)
实现-对于一个多TB的音乐收藏来说是糟糕的

稍微好一点的方法可能涉及在SQL中创建树结构,从而将在任何给定子文件夹步骤中搜索匹配项的可能候选项缩小到该子文件夹的大小。看起来仍然不雅观


我可以使用什么样的设计范例/包来帮助自己?显然,这将涉及许多聪明的哈希表。我只是在寻找一些正确方向的指针,来指导如何解决这个问题。(我也是一个完全的优化迷。)

现实是,这是一个困难的问题。您也从一个缺点开始:Python和mySQL不是用于此目的的最快工具

甚至iTunes也被抱怨,因为导入库和为新文件编制索引需要时间。你能想象出iTunes如此出色所花费的工时吗

你最好看一下主要开源音乐播放器的代码,比如

  • 米罗
  • 女妖
  • 鸣鸟

并尝试使他们的算法适应您的目的和Python习惯用法。

这其中最困难的部分是扫描目录,因为它可能很昂贵

但这是一个残酷的现实,因为你不能使用inotify等

在数据库中,只需创建节点类型记录:

create table node (
    nodeKey integer not null primary key,
    parentNode integer references node(nodeKey), // allow null for the root, or have root point to itself, whatever
    fullPathName varchar(2048),
    nodeName varchar(2048),
    nodeType varchar(1) // d = directory, f = file, or whatever else you want
)
这就是你的节点结构

可以使用“完整路径”列通过绝对路径快速查找任何内容

当文件移动时,只需重新计算路径

最后,扫描你的音乐文件。在unix中,您可以执行以下操作:

找到-类型f | sort>sortedListOfFiles

接下来,只需从数据库中提取所有路径名

从nodeType!='所在的节点中选择fullPathNamed'按完整路径名排序

现在您有了两个已排序的文件列表

通过DIFF(或comm)运行它们,您将得到一个已删除和新文件的列表。您将没有“移动”文件的列表。如果您想进行一些启发式操作,比较新文件和旧文件,并且它们具有相同的结尾(即…/唱片集/歌曲),尝试检测“移动”与新文件和旧文件,那么很好,没什么大不了的。值得一试

但是diff会在一瞬间给你微分

如果您有数以百万计的文件,那么,很抱歉,这将需要一些时间——但您已经知道,当您失去inotify功能时。如果你有,这将只是增量维护

当一个文件移动时,找到它的新绝对路径是很简单的,因为你可以向它的父级请求它的路径,然后简单地将你的名字附加到它上面。在那之后,除非你想爬,否则你不能爬树或任何东西。这是双向的

增编:

如果您想跟踪实际的名称更改,您可以获得更多的信息

您可以这样做:

find . -type f -print0 | xargs -0 ls -i | sort -n > sortedListOfFileWithInode
-print0和-0用于处理包含空格的文件。然而,文件名中的引号会破坏这一点。您最好通过python和fstat运行原始列表来获取inode。你可以在这里做不同的事情

这样做不仅仅是有名称,还可以获得文件的inode。inode是“真实”文件,一个目录将名称链接到inode。这就是如何在unix文件系统中将多个名称(硬链接)指向单个文件的方法,所有名称都指向同一索引节点

重命名文件时,inode将保持不变。在unix中,只有一个命令用于重命名和移动文件。mv重命名或移动文件时,只要文件在同一文件系统上,inode就保持不变

因此,使用inode和文件名可以捕获一些更有趣的信息,比如文件移动

如果他们删除该文件并添加一个新文件,则不会有任何帮助。但是您(很可能)能够知道它发生了,因为旧inode不太可能被重新用于新inode

因此,如果您有一个文件列表(按文件名排序):

如果有人删除并添加了歌曲2,您将获得类似

1234 song1.mp3
1237 song2.mp3
1236 song3.mp3
但如果你这样做:

mv song1.mp3 song4.mp3
您将获得:

1237 song2.mp3
1236 song3.mp3
1234 song4.mp3
另一个警告是,如果丢失驱动器并从备份中恢复,则所有inode都可能会更改,从而有效地强制重新生成索引


如果你真的喜欢冒险,你可以尝试使用扩展文件系统属性,并为文件分配其他有趣的元数据。虽然没有做太多的工作,但它也有很多可能性,而且可能存在一些看不见的危险,但是…

my
aggregate\u diggup
程序读取程序生成的扩展sha1sum.txt格式文件。这使我能够根据文件的sha1sum来定位文件。Diggup程序在其输出中存储mtime大小哈希和路径名。默认情况下,如果mtime和size匹配,它将跳过对文件进行散列。由我的聚合生成的索引由我的修改过的
1237 song2.mp3
1236 song3.mp3
1234 song4.mp3
files(file_key, hash, size, mtime, path, flag)
tracks(file_key, title, artist)
playlists(playlistid, index, file_key)
import os
import stat
# add new files:
update files set flag=0
for path in filesystem:
    s=os.stat(path)
    if stat.S_ISREG(s.st_mode):
        fetch first row of select mtime, hash, size from files where path=path
        if row is not None:
            if s.st_mtime == mtime and s.st_size == size:
                update files set flag=1 where path=path
                continue
        hash=hash_file(path)
        file_key="%s:%s" % (int(s.st_mtime), hash)
        insert or update files set file_key=file_key, size=s.st_size, mtime=s.st_mtime, hash=hash, flag=1 where path=path
# remove non-existent files:
delete from files where flag=0
import os
import re
music_directory = '/home/username/music'
music_type = '\.mp3$|\.wav$|\.etc$'
found_files = os.popen('find %s -type f -mtime 1 2>/dev/null' % music_directory)
for file in found_files:
    directory, filename = os.path.split()
    if re.compile(music_type).search(filename):
        #found a music file, check if you already have it in the library
        if filename in archived_music:
            continue
        #if you have gotten to this point, the music was not found in the arcchived music directory, so now perform whatever processing you would like to do on the full path found in file.