出于娱乐原因,我编写了一个 PHP 类,它用标签对文件进行分类,而不是以分层方式进行分类,标签以 +tag1+tag2+tagN+MD5.EXTENSION 的形式存储在文件名本身中,因此我坚持使用FS/OS 施加的字符限制 (255)。这是课程:
<?php
class TagFS
{
public $FS = null;
function __construct($FS)
{
if (is_dir($FS) === true)
{
$this->FS = $this->Path($FS);
}
}
function Add($path, $tag)
{
if (is_dir($path) === true)
{
$files = array_slice(scandir($path), 2);
foreach ($files as $file)
{
$this->Add($this->Path($path) . $file, $tag);
}
return true;
}
else if (is_file($path) === true)
{
$file = md5_file($path);
if (is_file($this->FS . $file) === false)
{
if (copy($path, $this->FS . $file) === false)
{
return false;
}
}
return $this->Link($this->FS . $file, $this->FS . '+' . $this->Tag($tag) . '+' . $file . '.' . strtolower(pathinfo($path, PATHINFO_EXTENSION)));
}
return false;
}
function Get($tag)
{
return glob($this->FS . '*+' . str_replace('+', '{+,+*+}', $this->Tag($tag)) . '+*', GLOB_BRACE);
}
function Link($source, $destination)
{
if (is_file($source) === true)
{
if (function_exists('link') === true)
{
return link($source, $destination);
}
if (is_file($destination) === false)
{
exec('fsutil hardlink create "' . $destination . '" "' . $source . '"');
if (is_file($destination) === true)
{
return true;
}
}
}
return false;
}
function Path($path)
{
if (file_exists($path) === true)
{
$path = str_replace('\\', '/', realpath($path));
if ((is_dir($path) === true) && ($path[strlen($path) - 1] != '/'))
{
$path .= '/';
}
return $path;
}
return false;
}
function Tag($string)
{
/*
TODO:
Remove (on Windows): . \ / : * ? " < > |
Remove (on *nix): . /
Remove (on TagFS): + * { }
Remove (on TagFS - Possibly!) -
Max Chars (in Windows) 255
Max Char (in *nix) 255
*/
$result = array_filter(array_unique(explode(' ', $string)));
if (empty($result) === false)
{
if (natcasesort($result) === true)
{
return strtolower(implode('+', $result));
}
}
return false;
}
}
?>
我相信这个系统对于几个小标签来说效果很好,但我的问题是当整个文件名的大小超过 255 个字符时。我应该采取什么方法来绕过文件名限制?我正在考虑在同一文件的几个硬链接上拆分标签,但排列可能会杀死系统。
还有其他方法可以解决这个问题吗?
编辑-一些用法示例:
<?php
$images = new TagFS('S:');
$images->Add('P:/xampplite/htdocs/tag/geoaki.png', 'geoaki logo');
$images->Add('P:/xampplite/htdocs/tag/cloud.jpg', 'geoaki cloud tag');
$images->Add('P:/xampplite/htdocs/tag/cloud.jpg', 'nuvem azul branco');
$images->Add('P:/xampplite/htdocs/tag/xml-full.gif', 'geoaki auto vin api service xml');
$images->Add('P:/xampplite/htdocs/tag/dunp3d-1.jpg', 'dunp logo');
$images->Add('P:/xampplite/htdocs/tag/d-proposta-04c.jpg', 'dunp logo');
/*
[0] => S:/+api+auto+geoaki+service+vin+xml+29be189cbc98fcb36a44d77acad13e18.gif
[1] => S:/+azul+branco+nuvem+4151ae7900f33788d0bba5fc6c29bee3.jpg
[2] => S:/+cloud+geoaki+tag+4151ae7900f33788d0bba5fc6c29bee3.jpg
[3] => S:/+dunp+logo+0cedeb6f66cbfc3974c6b7ad86f4fbd3.jpg
[4] => S:/+dunp+logo+8b9fcb119246bb6dcac1906ef964d565.jpg
[5] => S:/+geoaki+logo+5f5174c498ffbfd9ae49975ddfa2f6eb.png
*/
echo '<pre>';
print_r($images->Get('*'));
echo '</pre>';
/*
[0] => S:/+azul+branco+nuvem+4151ae7900f33788d0bba5fc6c29bee3.jpg
*/
echo '<pre>';
print_r($images->Get('azul nuvem'));
echo '</pre>';
/*
[0] => S:/+dunp+logo+0cedeb6f66cbfc3974c6b7ad86f4fbd3.jpg
[1] => S:/+dunp+logo+8b9fcb119246bb6dcac1906ef964d565.jpg
[2] => S:/+geoaki+logo+5f5174c498ffbfd9ae49975ddfa2f6eb.png
*/
echo '<pre>';
print_r($images->Get('logo'));
echo '</pre>';
/*
[0] => S:/+dunp+logo+0cedeb6f66cbfc3974c6b7ad86f4fbd3.jpg
[1] => S:/+dunp+logo+8b9fcb119246bb6dcac1906ef964d565.jpg
*/
echo '<pre>';
print_r($images->Get('logo dunp'));
echo '</pre>';
/*
[0] => S:/+geoaki+logo+5f5174c498ffbfd9ae49975ddfa2f6eb.png
*/
echo '<pre>';
print_r($images->Get('geo* logo'));
echo '</pre>';
?>
编辑:由于使用无服务器数据库或任何其他类型的查找表(XML、平面、键/值对等)的一些建议,我想澄清以下内容:虽然此代码是用 PHP 编写的,但其想法是将其移植到 Python 并用它制作一个桌面应用程序 - 这与 PHP 无关(当然除了示例之外)。此外,如果我必须使用某种查找表 我肯定会使用 SQLite 3,但我正在寻找的是一种除了文件系统(文件夹、文件和硬链接)之外不涉及任何其他附加“技术”的解决方案。
你可能会说我疯了,但我在这里试图实现两个简单的目标:1)保持系统“垃圾”免费(例如谁喜欢 Thumbs.db 或 DS_STORE?)和 2)保持文件易于识别(如果出于某种原因)查找表(在本例中为 SQLite)变得繁忙、损坏、丢失或忘记(例如在备份中)。
PS:这应该可以在 Linux、Mac 和 Windows(NTFS 下)上运行。