当有任何非法的char时,IO.FileInfo奇怪的异常“路径中的非法字符”

时间:2013-06-27 17:40:58

标签: .net vb.net file-io path fileinfo

我收到了“路径中的非法字符”异常,但该字符串似乎没有任何非法字符。

我如何解决这个问题?:

Private Sub Button_Send_Click(sender As Object, e As EventArgs) Handles Button_Send.Click

    For Each item As ListViewItem In ListView1.Items

        Clipboard.SetText(item.SubItems(0).Text)
        ' First I copy the text to the clipboard to ensure in Explorer.exe if all is ok and also ifthe file exists... and yes, it exists.
        ' The example text is this:
        ' C:\Electro\Nueva carpeta\Aggresivnes - Dance Or Die.mp3
        ' (without any quotes)


        ' ...But this throws an "not exists":
        If IO.File.Exists(item.SubItems(0).Text) Then MsgBox("exists") Else MsgBox("not exists")


        ' And here throws an exception of "*Illegal characters in path*" :
        Dim File As New IO.FileInfo(item.SubItems(0).Text)

    Next

End Su
  

更新2

我在我自己的代码中犯了一个错误,没有注意到在没有问题时返回true并且在问题存在时返回false,所以我决定删除我的旧更新并编辑这个:

我做了一个函数来验证(再次)文件名转换或字符串变量中的某些内容是否有任何无效字符,遵循@ Jim Mischel 答案指示:

#Region " Validate Windows FileName "

    ' [ Validate Windows FileName Function ]
    '
    ' By Elektro H@cker
    '
    ' Examples :
    ' MsgBox(Validate_Windows_FileName("C:\Test.txt"))  ' Result: True
    ' MsgBox(Validate_Windows_FileName("C:\Te|st.txt")) ' Result: False

    Private Function Validate_Windows_FileName(ByRef FileName As String)
        Dim Directory As String = Nothing
        Dim File As String = Nothing

        Try
            Directory = FileName.Substring(0, FileName.LastIndexOf("\")) & "\"
            File = FileName.Split("\").Last
        Catch
            If Directory Is Nothing Then File = FileName
        End Try

        If Directory Is Nothing AndAlso File Is Nothing Then Return False

        If Not Directory Is Nothing Then
            For Each InvalidCharacter As Char In IO.Path.GetInvalidPathChars
                If Directory.Contains(InvalidCharacter) Then
                    ' MsgBox(InvalidCharacter)
                    Return False
                End If
            Next
        End If

        If Not File Is Nothing Then
            For Each InvalidCharacter As Char In IO.Path.GetInvalidFileNameChars
                If File.Contains(InvalidCharacter) Then
                    ' MsgBox(InvalidCharacter)
                    Return False
                End If
            Next
        End If

        Return True ' FileName is valid
    End Function

#End Region

嗯...现在我使用该函数再次确保fullpath / filename和结果为“false”,这意味着该字符串包含一个无效的char,并且该char类似于“space”。

 MsgBox(Validate_Windows_FileName(item.SubItems(0).Text))

我不知道如何解决这个问题。

如果你想看到完整的课程,请点击这里:

Public Class Main

    Dim WinAmpTitle As String = String.Empty
    Dim WinAmpFile As String = String.Empty

    Dim Sendto_Path As String

    Dim WithEvents WinAmp_Timer As New Timer With {.Interval = 25, .Enabled = True}

    Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' Nothing to do here at the momento...
    End Sub

    Private Sub WinAmp_Timer_Tick(sender As Object, e As EventArgs) Handles WinAmp_Timer.Tick

        WinAmpTitle = WinAmpInfo.Title
        WinAmpFile = WinAmpInfo.FileName

        If Not TextBox_Title.Text = WinAmpTitle Then TextBox_Title.Text = WinAmpTitle

        If Not TextBox_Filename.Text = WinAmpFile Then TextBox_Filename.Text = WinAmpFile

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button_Copy.Click
        Dim item = ListView1.Items.Add(WinAmpFile)
        item.SubItems.Add(ComboBox_Sendto.Text)

    End Sub

    Private Sub Button_Send_Click(sender As Object, e As EventArgs) Handles Button_Send.Click

        For Each item As ListViewItem In ListView1.Items


            Clipboard.SetText(item.SubItems(0).Text)
            ' First I copy the text to the clipboard to ensure in Explorer.exe if the file exists... and yes, it exists.
            ' The example text is this:
            ' C:\Electro\Nueva carpeta\Aggresivnes - Dance Or Die.mp3
            ' (without any quotes)


            ' ...But this throws an "not exists":
            If IO.File.Exists(item.SubItems(0).Text) Then MsgBox("exists") Else MsgBox("not exists")

            MsgBox(Validate_Windows_FileName(item.SubItems(0).Text)) ' Result: False (any invalid character)


            ' Here, an exception: "Illegal characters in path" :
            Dim File As New IO.FileInfo(item.SubItems(0).Text)

            ' If item.SubItems(1).Text.ToLower = "electro" Then Sendto_Path = "C:\Electro"
            ' If item.SubItems(1).Text.ToLower = "techno" Then Sendto_Path = "C:\Techno"
            ' If item.SubItems(1).Text.ToLower = "trance" Then Sendto_Path = "C:\Trance"

            'IO.File.Copy(File.FullName, IO.Path.Combine(Sendto_Path, File.Name))

        Next

    End Sub


#Region " Validate Windows FileName "

    ' [ Validate Windows FileName Function ]
    '
    ' By Elektro H@cker
    '
    ' Examples :
    ' MsgBox(Validate_Windows_FileName("C:\Test.txt"))  ' Result: True
    ' MsgBox(Validate_Windows_FileName("C:\Te|st.txt")) ' Result: False

    Private Function Validate_Windows_FileName(ByRef FileName As String)
        Dim Directory As String = Nothing
        Dim File As String = Nothing

        Try
            Directory = FileName.Substring(0, FileName.LastIndexOf("\")) & "\"
            File = FileName.Split("\").Last
        Catch
            If Directory Is Nothing Then File = FileName
        End Try

        If Directory Is Nothing AndAlso File Is Nothing Then Return False

        If Not Directory Is Nothing Then
            For Each InvalidCharacter As Char In IO.Path.GetInvalidPathChars
                If Directory.Contains(InvalidCharacter) Then
                    ' MsgBox(InvalidCharacter)
                    Return False
                End If
            Next
        End If

        If Not File Is Nothing Then
            For Each InvalidCharacter As Char In IO.Path.GetInvalidFileNameChars
                If File.Contains(InvalidCharacter) Then
                    ' MsgBox(InvalidCharacter)
                    Return False
                End If
            Next
        End If

        Return True ' FileName is valid
    End Function

#End Region

End Class

......第二部分(我认为不太重要):

#Region " WinAmp Info "

' [ WinAmp Info Functions ]
'
' // By Elektro H@cker
'
' Examples:
' MsgBox(WinAmpInfo.Title)    ' Result: Artist - Title
' MsgBox(WinAmpInfo.FileName) ' Result: C:\Title.ext

Public Class WinAmpInfo

    Private Const WinampClassName As String = "Winamp v1.x"

    Private Declare Auto Function FindWindow Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    Private Declare Auto Function GetWindowText Lib "user32" (ByVal hwnd As IntPtr, ByVal lpString As String, ByVal cch As Integer) As Integer
    Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, ByRef lpdwProcessId As Long) As Long
    Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByRef lpBuffer As Byte, ByVal nSize As Long, ByRef lpNumberOfBytesRead As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

    Public Shared Function Title() As String

        Dim hwnd As IntPtr = FindWindow(WinampClassName, vbNullString)

        Dim lpText As String = String.Empty
        Dim strTitle As String = String.Empty

        Dim intLength As Integer = 0
        Dim intName As Integer = 0
        Dim intLeft As Integer = 0
        Dim intRight As Integer = 0
        Dim intDot As Integer = 0

        If hwnd.Equals(IntPtr.Zero) Then Return "WinAmp is not running"

        lpText = New String(Chr(0), 100)
        intLength = GetWindowText(hwnd, lpText, lpText.Length)

        If (intLength <= 0) _
        OrElse (intLength > lpText.Length) _
        Then Return "Unknown"

        strTitle = lpText.Substring(0, intLength)
        intName = strTitle.IndexOf(" - Winamp")
        intLeft = strTitle.IndexOf("[")
        intRight = strTitle.IndexOf("]")

        If (intName >= 0) _
        AndAlso (intLeft >= 0) _
        AndAlso (intName < intLeft) _
        AndAlso (intRight >= 0) _
        AndAlso (intLeft + 1 < intRight) _
        Then Return strTitle.Substring(intLeft + 1, intRight - intLeft - 1)

        If (strTitle.EndsWith(" - Winamp")) _
        AndAlso (strTitle.Length > " - Winamp".Length) _
        Then strTitle = strTitle.Substring(0, strTitle.Length - " - Winamp".Length)

        intDot = strTitle.IndexOf(".")

        If (intDot > 0) _
        AndAlso (IsNumeric(strTitle.Substring(0, intDot))) _
        Then strTitle = strTitle.Remove(0, intDot + 1)

        Return strTitle.Trim

    End Function

    Public Shared Function FileName() As String

        Dim lp As Long, lpWinamp As Long, iIndex As Long, PID As Long, bRet As Long, dwRead As Long
        Dim Buffer(260) As Byte

        Dim hWndWinamp As IntPtr = FindWindow(WinampClassName, vbNullString)
        If hWndWinamp = 0 Then Return Nothing

        iIndex = SendMessage(hWndWinamp, &H400, 0, 125)

        lp = SendMessage(hWndWinamp, &H400, iIndex, 211)
        If lp = 0 Then Return Nothing

        Call GetWindowThreadProcessId(hWndWinamp, PID)

        lpWinamp = OpenProcess(&H10, 0, PID)
        If lpWinamp = 0 Then Return Nothing

        bRet = ReadProcessMemory(lpWinamp, lp, Buffer(0), 260, dwRead)

        Call CloseHandle(lpWinamp)

        Return System.Text.UnicodeEncoding.Default.GetString(Buffer)

    End Function

End Class

#End Region
  

更新3:

我的新尝试...所有解释,我得到一个无效的字符,我不知道为什么......

Private Sub Button_Send_Click(sender As Object, e As EventArgs) Handles Button_Send.Click

    For Each item As ListViewItem In ListView1.Items

        Dim filenameee As String = item.SubItems(0).Text.Trim ' The trim is...fuck, is just 'cause I don't know what more try to get a valid path...)

        Clipboard.SetText(filenameee) ' result: "C:\Test.mp3" (Without any double quote of course)

        ' ...but this launchs an "not exists" msgbox with the filename "C:\Test.mp3":
        If IO.File.Exists(filenameee) Then MsgBox("exists") Else MsgBox("not exists")

        MsgBox(filenameee) ' this showns "C:\Test.mp3" /without double quotes)
        MsgBox("filename is vlaid?:" & Validate_Windows_FileName(filenameee)) ' Result: False (path is invalid) (REALLY!!!!??? WTF)


        ' Here, an exception: "Illegal characters in path" :
        Dim File As New IO.FileInfo(item.SubItems(0).Text) ' (REALLY!!!!???)

    Next

End Sub
  

更新4:

照片:

应用程序本身:

enter image description here

(C:\ Test.mp3是文件名变量文本)

Io.file.exists comprobation:

enter image description here

显示filenameee变量内容:

enter image description here

如果文件名有效,

检查:

enter image description here

在filenameee中显示假定的非法字符:

enter image description here

(空格?)

例外:

enter image description here

  

更新5

我认为真正的问题出现在我的 winamp 类的“filename()”函数中,我在UPDATENº2中发布了这个函数:

Return System.Text.UnicodeEncoding.Default.GetString(Buffer)

因为它似乎返回了一个有效的字符串,如图所示,但在“Autos”中似乎是一个大字符串:

enter image description here

所以,如果有人可以帮我解决这个问题......

感谢。

  

更新6:

这是有效的,我想知道是否存在一个方法或某些东西来改进这个以避免使用For循环:

Dim i As Int32 = 0
For Each by In System.Text.Encoding.Default.GetString(Buffer)
    If by = Nothing Then Exit For 'MsgBox(i)
    i += 1
Next

Return System.Text.Encoding.Default.GetString(Buffer, 0, i)

2 个答案:

答案 0 :(得分:4)

根据无效路径字符(GetInvalidPathChars)和无效的文件名字符(GetInvalidFilenameChars)检查文件名。这应该告诉你哪些角色不好。

请注意,File.Exists不会“抛出”任何内容。 返回 false表示该文件不存在。正如the documentation所述:

  

Exists方法不应用于路径验证,此方法仅检查路径中指定的文件是否存在。将无效路径传递给Exists将返回false。要检查路径是否包含任何无效字符,可以调用GetInvalidPathChars方法来检索对文件系统无效的字符。您还可以创建正则表达式来测试路径是否对您的环境有效。

换句话说,File.Exists并不关心你是否将垃圾传递给它。它会告诉您具有该无用名称的文件不存在。它不会告诉你你给它一个错误的路径名称。

评论后更新

我不确切地知道您在ReadProcessMemory等处做了什么,但可能是您的问题与此代码有关:

    bRet = ReadProcessMemory(lpWinamp, lp, Buffer(0), 260, dwRead)

    Call CloseHandle(lpWinamp)

    Return System.Text.UnicodeEncoding.Default.GetString(Buffer)

这里你将数据读入一个260字节的缓冲区,然后创建一个字符串,但你并没有告诉GetString要使用多少字节的缓冲区,所以它会使用(或尝试使用)所有这些。所以你最终会在你的字符串的末尾找到各种垃圾(可能)。

此外,我不清楚您是否尝试使用Unicode编码或默认编码。你有System.Text.UnicodeEncoding.Default。这将为您提供Default代码页的编码,这是系统的默认ANSI代码页。如果您需要默认编码,请使用System.Text.Encoding.Default

假设您期望以null结尾的ANSI字符串,那么在调用GetString之前,您需要让代码找到字符串的长度。通过在缓冲区中搜索前0个字节来做到这一点。这会给你长度,然后你可以打电话给GetString(buffer, 0, length)

要查找长度,请执行以下操作:

Dim Len as Integer
For Len = 0 to 260
    if Buffer(Len) = 0 Then Exit For
Next
Return System.Text.Encoding.Default.GetString(Buffer, 0, Len)

答案 1 :(得分:3)

修改 从您的评论和我可以看到的文件路径(因为我必须放大屏幕截图),有空格。

'I've left the trim here.
 Dim filenameee As String = item.SubItems(0).Text.Trim
'To remove remainding whitespace.
 filenamee = filenamee.Replace(" ", "")

'File.Exists(file_path) - item.subitem(0).text needs to show a valid path file.

  If IO.File.Exists(filenameee) Then MsgBox("exists") 

  Dim File As New IO.FileInfo(item.SubItems(0).Text)

Else MsgBox("not exists")

文件路径MSDN:

http://msdn.microsoft.com/en-us/library/783hax6d(v=VS.80).aspx

是的,如果没有返回完整路径,则需要设置缓冲区并读取以接受所需的最小字节数。这已经在另一个答案中得到了解决,所以不要重申它,但提供了一个链接。

IO流读取MSDN:

http://msdn.microsoft.com/en-US/library/system.io.stream.read(v=VS.80).aspx