6

Я использую Windows 8.1 с Windows Explorer. Кэш изображений («thumbs.db») создается, когда я захожу в папку, содержащую видео, фото или другие подобные файлы. У меня проблема с этим, потому что у меня есть несколько папок с большими видео и фотографиями, которые постоянно меняются. Каждый раз, когда я открываю папку, содержащую эти файлы, мне приходится ждать несколько секунд, пока создается кэш миниатюр.

Одним из обходных путей может быть отключение кэша миниатюр. Но мне нравится видеть эскизы, так что это не решение для меня. Вместо этого я хотел бы вызывать пакет или другую программу каждые x секунд, которая рекурсивно создает эскизы Windows. Я мог тогда открыть папки без задержки.

Как я могу сделать это?

4 ответа4

3

Вот сценарий PowerShell, который я написал, который должен делать то, что вам нужно.

Я взял логику из этой темы: https://stackoverflow.com/questions/3555799/how-do-i-refresh-a-files-thumbnail-in-windows-explorer и превратил ее в скрипт, который можно запустить как запланированное задание в windows.

Для его использования вам потребуется установить .net4.0 и PowerShell 3.0, иначе у вас будут ошибки. На данный момент у вас, вероятно, есть .net4.0, но вам, вероятно, понадобится PowerShell 3.0

Сохраните следующее в файл с именем thumb_generate.ps1

param ([string]$path,[string]$ext)
function Refresh-Explorer 
{  
   $code = @'  
   [System.Runtime.InteropServices.DllImport("Shell32.dll")]   
   public static extern Int32 SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] String pszName, IntPtr pbc, out IntPtr ppidl, UInt32 sfgaoIn, out UInt32 psfgaoOut);

   [System.Runtime.InteropServices.DllImport("Shell32.dll")]   
   private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);

   [System.Runtime.InteropServices.DllImport("Shell32.dll")]   
   private static extern int ILFree(IntPtr pidl);    

   public static void Refresh(string path)  {
    uint iAttribute;
    IntPtr pidl;
    SHParseDisplayName(path, IntPtr.Zero, out pidl, 0, out iAttribute);  
    SHChangeNotify(0x00002000, 0x1000, IntPtr.Zero, IntPtr.Zero); 
    ILFree(pidl); 
}  
'@  

    Add-Type -MemberDefinition $code -Namespace MyWinAPI -Name Explorer   
    [MyWinAPI.Explorer]::Refresh($path)  
} 

cls
if([System.String]::IsNullOrEmpty($path))
{
   Write-Host "Path cannot be empty."
   Write-Host "Example:  .\thumb_generate.ps1 -path ""C:\"" -ext ""jpg"""
   return
}
if([System.String]::IsNullOrEmpty($path))
{
   Write-Host "Extension cannot be empty."
   Write-Host "Example:  .\thumb_generate.ps1 -path ""C:\"" -ext ""jpg"""
   return
}

$fileExtension = "*." + $ext
Write-Host -ForegroundColor Green "---Thumbnail generation for Windows 7/8---"
Write-Host -ForegroundColor Green "----PowerShell 3.0 & .Net 4.0 required----"
Write-Host "Path: "  $path
Write-Host "Extension: " $fileExtension
Write-Host 
if (Test-Path $path) 
{
   Write-Host "Path Exists, begin generation thumbnails"

   $images = [System.IO.Directory]::EnumerateFiles($path,$fileExtension,"AllDirectories")
   Foreach($image in $images)
   {
       try
       {
          $file = New-Object System.IO.FileInfo($image)
          Write-Host $file.FullName
          $fStream = $file.Open([System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,[System.IO.FileShare]::None)

          $firstbyte = New-Object Byte[] 1
          $result = $fStream.Read($firstbyte,0,1)
       }
       catch
       {
          Write-Host -ForegroundColor Red "An error occured on file: " + $file.FullName
       }
       $fStream.Close();
   }
    Refresh-Explorer
}
else
{
  "Path Doesn't Exist, Exiting..."
}

Затем выполните его из командной строки PowerShell со следующими параметрами:

.\thumb_generate.ps1 -path "C:\PathToImages\"  -ext "jpg"

На самом деле, любое расширение файла должно работать. Он будет рекурсивно просматривать все каталоги. Один недостаток - это только один тип файла одновременно, но можно запустить несколько заданий, которые просто используют другое расширение файла. По сути, скрипт открывает каждый файл и читает только первый байт, что достаточно для принудительного обновления файла thumbs.db.

Редактировать Я изменил скрипт, чтобы включить часть обновления оболочки, опубликованную выше. Кажется, он работает в моей системе, хотя у меня нет тысяч изображений для тестирования. Это объединяет чтение первых нескольких байтов файла с последующим принудительным обновлением миниатюр.

2

Я могу придумать два способа ускорить создание миниатюр:

  1. Уменьшить размер миниатюры (подробнее)
  2. Напишите программу, которая периодически обновляет эскизы новых файлов

Что касается второго метода, я не знаю продукта, который это делает, поэтому вам нужно написать свой собственный. Вот полезная ссылка:Как обновить миниатюру файла в проводнике Windows? ,

Этот пост предлагает и включает исходный текст программы на C #, которая выполняет это, читая первый байт файла. Windows обновляет миниатюру, когда программа закрывает файл.

Принятый ответ более просто уведомляет Windows о том, что файл изменился, и опубликованное решение не нуждается в его чтении.

Моя версия (не проверена):

public static void refreshThumbnail(string path)
{
    try
    {
        uint iAttribute;
        IntPtr pidl;
        SHParseDisplayName(path, IntPtr.Zero, out pidl, 0, out iAttribute);
        SHChangeNotify(
            (uint)ShellChangeNotificationEvents.SHCNE_UPDATEITEM,
            (uint)ShellChangeNotificationFlags.SHCNF_FLUSH,
            pidl,
            IntPtr.Zero);
        ILFree(pidl);

    }
    catch { }
}
1

Другой фрагмент программы, который должен обновить кэш миниатюр, используя COM-интерфейс IThumbnailCache (C++). Насколько мне известно, нет никакого предварительно скомпилированного инструмента для этой задачи.

MSDN говорит: «Если параметр flags для IThumbnailCache:: GetThumbnail включает флаг WTS_EXTRACT, а миниатюра еще не кэширована, миниатюра будет извлечена и помещена в кэш»

CoInitialize(NULL);

IThumbnailCache *cache;
HRESULT hr = CoCreateInstance(CLSID_LocalThumbnailCache, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&cache));
if (SUCCEEDED(hr))
{
    <loop over files>
    {
        cache->GetThumbnail(<shell item for file>, <required size>, WTS_EXTRACT, NULL, NULL, NULL);
        cache->Release();
    }
}
-2

Проблема довольно сложная. Лучше всего разработать приложение специально для этой цели.

Опция 1:

Найдите * .jpg, * .avi и т.д., И все они должны быть кэшированы.

Вариант 2а:

Создайте пакетный скрипт для создания миниатюр вручную. Пример (адаптироваться к вашим потребностям):

mkdir thumbjunk
for f in *.jpg
do convert $f -thumbnail 100x80 thumbjunk/$f.gif

Рекурсивный:

find * -prune -name '*.jpg' \
-exec convert '{}' -thumbnail 100x80 thumbjunk/'{}'.gif 

Вариант 2b:

Это для видео файлов, ffmpeg это инструмент.

Пример:

ffmpeg -ss 00:01:00 -i testavi.avi -vf 'select=not(mod(n\,1000)),scale=320:240,tile=2x3' testavi.png

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .