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.
我正在尝试为我的电影 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
is1234
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.