Powershell 和包含 non-ASCII 个字符的文件名(例如 Æ)

Powershell and filenames with non-ASCII characters (e.g. Æ)

我正在尝试为我的电影 collection 编制索引,但在这样做时 运行 遇到了一个问题,即由于特殊字符,至少有一个影片在导入阶段被跳过。代码会跳过“Æon Flux”,因为它以 Æ 开头。请问有人知道如何更正吗?

Clear-Host

# Variables:
$movie_dir = "K:\Movies"

# Because reasons...
$PSDefaultParameterValues['*:Encoding'] = 'utf8'

# Connect to the library MySQL.Data.dll
Add-Type -Path 'C:\Program Files (x86)\MySQL\Connector NET 8.0\Assemblies\v4.8\MySql.Data.dll'
 
# Create a MySQL Database connection variable that qualifies:
$Connection = [MySql.Data.MySqlClient.MySqlConnection]@{ConnectionString='server=127.0.0.1;uid=username;pwd=password;database=media'}
$Connection.Open()

# Drop the table to clear all entries.
$sql_drop_table = New-Object MySql.Data.MySqlClient.MySqlCommand
$sql_drop_table.Connection = $Connection
$sql_drop_table.CommandText = 'DROP TABLE Movies'
$sql_drop_table.ExecuteNonQuery() | Out-Null

# (Re)create the table.
$sql_create_table = New-Object MySql.Data.MySqlClient.MySqlCommand
$sql_create_table.Connection = $Connection
$sql_create_table.CommandText = 'create table Movies(movie_id INT NOT NULL AUTO_INCREMENT, movie_title VARCHAR(255) NOT NULL, movie_file_date INT, movie_IMDB_id INT, PRIMARY KEY (movie_id))'
$sql_create_table.ExecuteNonQuery() | Out-Null

$movies = Get-ChildItem $movie_dir -File -include *.mp4 -Recurse -Depth 1 |
    Select-Object -ExpandProperty FullName |
    Sort-Object |
    Get-Unique |
    where{$_ -ne ""}

foreach ($movie in $movies)
{
    # .net function to get just the filename (movie title).
    $title = [System.IO.Path]::GetFileNameWithoutExtension($movie)
    # Get the creation date of the movie and reformat it to yearmonthday.
    $add_date = (Get-ChildItem $movie).CreationTime.toString("yyyyMMdd")

    $query = "INSERT INTO Movies(movie_id, movie_title, movie_file_date) VALUES(NULL, @title, $add_date)"
    $command = $connection.CreateCommand()
    $command.CommandText = $query
    # Sanatize single quotes in filenames for input.
    $command.Parameters.AddWithValue("@title", $title) | Out-Null
    $command.ExecuteNonQuery() | Out-Null
}

# Close the MySQL connection.
$Connection.Close()

Write-Host
Write-Host("Added") $movies.Count ("movies.")

我不认为是 Get-ChildItem 跳过了带有那个特殊字符的文件。更有可能的是,您需要告诉 MySql 使用 UTF-8。
为此,请查看 How to make MySQL handle UTF-8 properly

至于你的代码,我会改变这个:

$movies = Get-ChildItem $movie_dir -File -include *.mp4 -Recurse -Depth 1 |
    Select-Object -ExpandProperty FullName |
    Sort-Object |
    Get-Unique |
    where{$_ -ne ""}

进入

$movies = Get-ChildItem -Path $movie_dir -File -Filter '*.mp4' -Recurse -Depth 1 | Sort-Object -Property FullName

并从那里开始使用 FileInfo 对象:

foreach ($movie in $movies) {
    $title = $movie.BaseName
    # Get the creation date of the movie and reformat it to yearmonthday.
    $add_date = '{0}:yyyyMMdd}' -f $movie.CreationTime
    . . .
}

虽然 Æ 不是 ASCII 字符,但它不是“特殊字符”,所以我编辑了问题标题和标签以反映这一点。

ExecuteNonQuery() returns命令影响的行数;在 $command 的情况下,它是插入的行数。您正在丢弃此值,但是...

$command.ExecuteNonQuery() | Out-Null

...这会掩盖 INSERT 失败时的问题。相反,测试结果并做出适当的回应...

if ($command.ExecuteNonQuery() -eq 1)
{
    Write-Host -Message "Successfully inserted movie ""$title""."
}
else
{
    Write-Warning -Message "Failed to insert movie ""$title""."
}

这将明确问题出在与文件系统或数据库的交互上。

一些其他注意事项:

  • MySqlCommand 在您使用完后实现 IDisposable interface and so each instance should be disposed...

    $query = "INSERT INTO Movies(movie_id, movie_title, movie_file_date) VALUES(NULL, @title, $add_date)"
    $command = $connection.CreateCommand()
    try
    {
        $command.CommandText = $query
        # Sanatize single quotes in filenames for input.
        $command.Parameters.AddWithValue("@title", $title) | Out-Null
        if ($command.ExecuteNonQuery() -eq 1)
        {
            Write-Host -Message "Successfully inserted movie ""$title""."
        }
        else
        {
            Write-Warning -Message "Failed to insert movie ""$title""."
        }
    }
    finally
    {
        $command.Dispose()
    }
    

    ...$sql_drop_table$sql_create_table 也是如此。 finally 块中的代码将 运行 即使从 try block.

    中抛出错误也是如此
  • 请参阅 Difference with Parameters.Add and Parameters.AddWithValue 及其链接了解为什么 AddWithValue() 会出现问题。

  • 而不是...

    Write-Host("Added") $movies.Count ("movies.")
    

    ...构建此消息的更典型方法是 string interpolation...

    Write-Host "Added $($movies.Count) movies."
    

    ...或 format operator...

    Write-Host ('Added {0} movies.' -f $movies.Count)
    

    你也可以合并 numeric format strings, so if $movies.Count is 1234 and $PSCulture is 'en-US' 然后...

    Write-Host "Added $($movies.Count.ToString('N0')) movies."
    

    ...和...

    Write-Host ('Added {0:N0} movies.' -f $movies.Count)
    

    ...都会写...

    Added 1,234 movies.