Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.68/19: Рейтинг темы: голосов - 19, средняя оценка - 4.68
7 / 7 / 0
Регистрация: 21.12.2016
Сообщений: 152

FindFirstFile не корректно определяет имена файлов с диакритическими знаками

18.04.2023, 21:49. Показов 4892. Ответов 88
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток.

Делаю програмку, необходимо получить содержимое папки (список папок и файлов) и после определить ФАЙЛ или ПАПКА и другие атрибуты. Как всегда делал раньше, через API "FindFirstFile", привык, удобно и есть заготовки кода. И вот, выясняется такая неприятная ситуация. На компьютере есть несколько видео файлов с испанскими названиями.
В них содержатся слова с Диакритическими знаками.

например: "Niño cristiano GANA! concurso secular YouTube.flv español.mp4"

Как выяснилось, "FindFirstFile" возвращая имя этого файла, возвращает его как:
"Nino cristiano GANA! concurso secular YouTube.flv espanol.mp4" - ну и в дальнейшем соответственно вся обработка рушится.

Вот код, давно когда-то нашёл на просторах интернета и всегда использовал:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    Dim bstFileName As String
    Dim lngFileCount As Long
    Dim lngAPIReturn As Long
    Dim bstPath As String
    Dim bstCinteria As String
    Dim abstFileNames() As String
    Dim lngHSearch As Long
    Dim udtWFD As WIN32_FIND_DATA
   
    bstCinteria = iCinteria
    bstPath = iPath
    
    lngHSearch = INVALID_HANDLE_VALUE
    lngHSearch = FindFirstFile(bstPath & iCinteria, udtWFD)
    lngFileCount = -1&
       
    If lngHSearch <> INVALID_HANDLE_VALUE Then
        Do
            bstFileName = Left(udtWFD.cFileName, VBA.InStr(1, udtWFD.cFileName, Chr(0)) - 1) ', vbNullString)
            Stop
            If (bstFileName <> ".") And (bstFileName <> "..") Then
                lngFileCount = lngFileCount + 1
                ReDim Preserve abstFileNames(0& To lngFileCount) As String
                abstFileNames(lngFileCount) = bstFileName
            End If
            lngAPIReturn = FindNextFile(lngHSearch, udtWFD)
        Loop Until lngAPIReturn = 0&
        FindClose lngHSearch
    End If
 
    oFileNames = abstFileNames
    oMaxIdx = lngFileCount

Облазил весь интернет, так и не понял, как можно исправить данную ситуацию.

Читал на каком-то зарубежном С++ форуме, что используют FindFirstFileW и WIN32_FIND_DATAW
Но как это оформить и поможет ли это в моём случае, до конца так и не понял. Даже не понял, как объявить правильно на vb6.

Если не затруднит, подскажите кто знает, решение. А лучше готовый кусок кода. Буду очень признателен.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
18.04.2023, 21:49
Ответы с готовыми решениями:

Обработка символов с диакритическими знаками
Привет. Dim macron As String = &quot;M̄acron&quot; MsgBox(macron) For n As Integer = 0 To macron.Length - 1 MsgBox(macron(n)) ...

Укоротить длинные имена до размера K символов, а те имена, которые короче K символов дополнить восклицательными знаками
Дан список из N имён. Необходимо укоротить длинные имена до размера K символов, а те имена, которые короче K символов дополнить...

Работа с файлами поиск файлов FindFirstFile,FindNextFile
Доброго времени суток, спустя долгое время, с измученным гуглом я нашел решение проблемы, но создалась еще одна проблема ...

88
1402 / 860 / 93
Регистрация: 08.02.2017
Сообщений: 3,671
Записей в блоге: 2
30.09.2023, 10:18
Студворк — интернет-сервис помощи студентам
Есть не очень ясный момент, как с именами >260 символов поступать. Что я сейчас и проверю. У себя я не нашел такхи файлов, придется создать..
0
Вернулся
 Аватар для HackerVlad
1748 / 644 / 45
Регистрация: 10.09.2021
Сообщений: 2,786
30.09.2023, 10:58
Цитата Сообщение от testuser2 Посмотреть сообщение
как с именами >260 символов поступать
Ограничение в MAX_PATH было снято только в Windows 10, а у тебя, насколько я помню, Windows 8. Поэтому я не понимаю чего ты тут сможешь добиться вообще, если границы операционной системы раздвинуть не получится. :-)

Добавлено через 4 минуты
testuser2, читай MSDN: https://learn.microsoft.com/ru... s=registry
0
1402 / 860 / 93
Регистрация: 08.02.2017
Сообщений: 3,671
Записей в блоге: 2
30.09.2023, 11:05
На Хабре пишут
В приложениях, которые используют Win API для работы с файлами, рецепт избавления от ограничения MAX_PATH был известен с незапамятных времён – необходимо было использовать Unicode версию функции с окончанием «W» для работы с директорией или файлом и начинать путь с префикса \\?\. Это давало возможность использовать пути длинной до 32767 символов.

В Windows 10 (1607) поведение функций для работы с файлами изменилось: появилась возможность отключить проверку ограничений MAX_PATH на уровне системы.
Но у меня действительно пока не получилось создать такой файл
0
Вернулся
 Аватар для HackerVlad
1748 / 644 / 45
Регистрация: 10.09.2021
Сообщений: 2,786
30.09.2023, 11:08
Цитата Сообщение от testuser2 Посмотреть сообщение
Но у меня действительно пока не получилось создать такой файл
Ты его и не сможешь создать. Длина файла чтобы была 260 символов? Ты шутишь? Даже весь путь всех папок не может превышать 260 символов - 12 символов
0
1402 / 860 / 93
Регистрация: 08.02.2017
Сообщений: 3,671
Записей в блоге: 2
30.09.2023, 14:42
Вот код. Меньше 260 получается, больше - нет
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Private Declare Function CreateFileW Lib "Kernel32" (ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByRef lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function CloseHandle Lib "Kernel32" (ByVal hObject As Long) As Long
 
Private Const GENERIC_READ As Long = &H80000000
Private Const GENERIC_WRITE As Long = &H40000000
Private Const FILE_SHARE_WRITE As Long = &H2
Private Const FILE_SHARE_READ As Long = &H1
Private Const CREATE_NEW As Long = 1
Private Const CREATE_ALWAYS As Long = 2
Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80
Private Const FILE_FLAG_OVERLAPPED As Long = &H40000000
Private Const OPEN_EXISTING As Long = 3
Private Const INVALID_FILE_HANDLE = -1 '&HFFFFFFFF
 
Sub testCreateFl()
    Dim hNewFile&, sTemp$
'    sTemp = "\\?\D:\test\newFile3.txt"
    sTemp = "\\?\D:\test\" & String(270&, "l") & ".txt"
    hNewFile = CreateFileW(StrPtr(sTemp), GENERIC_WRITE Or GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, CREATE_NEW, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_OVERLAPPED, 0)
    CloseHandle hNewFile
End Sub
Добавлено через 7 минут
Я еще помню давно, то ли на XP, то ли 7 была прога - кэширующий прокси-сервер HandyCache, так вот она создавала файлы кэша с такими длинными именами. Была трабла с этими файлами, их было очен много и нельзя было удалить из проводника, в добавок еще повреждены были.

Добавлено через 3 часа 24 минуты
Цитата Сообщение от HackerVlad Посмотреть сообщение
If Right$(Trim$(Str$(all_cnt)), 3) = "000" Then ' Каждая тысяча строк
If Interrupt = True Then
DoEvents ' Прерывание
End If
End If
Проверку я бы лучше сделал так
Visual Basic
1
If (all_cnt mod 1000) = 0 Then
DoEvents конечно бутылочное горлышко в скорости. В одной старой книжке по VB (единственной которую я читал) есть такой код (там еще есть разные советы)
Visual Basic
1
2
3
4
5
6
7
8
Declare Function GetInputState Lib "user32" _
Alias "GetInputState" () As Long 
 
For c = 1 To 100000
temp = 2 * 2 * 2
If GetInputState() Then DoEvents ' здесь 312 мс.
DoEvents ' а здесь время выполнения цикла 6543 мс. !!!
Next c
При таком способе указатель мыши будет постоянно показывать загрузку. Я придумал (может где-то увидел, х.з. не помню) др. способ, более чувствительный к активности юзера. По скорости почти не отличается от GetInputState
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Private Declare PtrSafe Sub GetLastInputInfo Lib "user32" (ByRef plii As LASTINPUTINFO)
Private Type LASTINPUTINFO
    cbSize As Long
    dwTime As Long
End Type
 
Sub sfsffsdfd()
   Dim t!, c&, lii As LASTINPUTINFO, tm&
   
   t = Timer
   For c = 1 To 300000000
        
        'If GetInputState() Then DoEvents
        GetLastInputInfo lii
        If tm <> lii.dwTime Then
            tm = lii.dwTime
            DoEvents
        End If
   Next c
   debug.print Timer - t
End Sub
0
Вернулся
 Аватар для HackerVlad
1748 / 644 / 45
Регистрация: 10.09.2021
Сообщений: 2,786
30.09.2023, 16:09
testuser2, молодец!
0
1402 / 860 / 93
Регистрация: 08.02.2017
Сообщений: 3,671
Записей в блоге: 2
30.09.2023, 16:31
Забыл,
Visual Basic
1
lii.cbSize = Len(lii)
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18035 / 7738 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
30.09.2023, 17:21
Цитата Сообщение от HackerVlad Посмотреть сообщение
Итак каждую 1000 строк например подкачивать
У себя я обычно чанками по 100 элементов выделяю, и каждую итерацию проверяю не достигло ли границы.
Цитата Сообщение от HackerVlad Посмотреть сообщение
Плюс добавил рекурсию.
Если подпапок очень много, чтобы не перегрузить стек рекурсивными вызовами, юзают линейный алгоритм через списки.
Цитата Сообщение от HackerVlad Посмотреть сообщение
Ты его и не сможешь создать. Длина файла чтобы была 260 символов? Ты шутишь? Даже весь путь всех папок не может превышать 260 символов - 12 символов
https://www.cyberforum.ru/blog... og731.html
Цитата Сообщение от HackerVlad Посмотреть сообщение
Ограничение в MAX_PATH было снято только в Windows 10, а у тебя, насколько я помню, Windows 8. Поэтому я не понимаю чего ты тут сможешь добиться вообще, если границы операционной системы раздвинуть не получится. :-)
Там не всё так просто. Для снятия ограничения в Win10+ нужно прописывать в манифесте приложения параметр longPathAware, и кроме того в групповых политиках должна быть включена соответствеющая настройка.
Цитата Сообщение от HackerVlad Посмотреть сообщение
Когда функция завершается VB сам очищает всё лишнее из памяти, все переменные.
Удаление указателя нужно, чтобы VB при автоматической очистке памяти не сделал декремент кол-ва ссылок на объект, на который он сам не делал ссылку. Получится краш двойной очистки.
2
1402 / 860 / 93
Регистрация: 08.02.2017
Сообщений: 3,671
Записей в блоге: 2
30.09.2023, 17:29
Цитата Сообщение от HackerVlad Посмотреть сообщение
например, в корне диска, первые две позиции могут быть уже другими, а не "." и ".."
Допустим как-нибудь так объехать ситуацию..
Кликните здесь для просмотра всего текста
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    If hSearch <> INVALID_HANDLE_VALUE Then
        lpStr = VarPtr(WFD.cFileName(0))  '= VarPtr(WFD.dwReserved1) + 4
        PutMem4 VarPtr(DirName), lpStr    'меняем указатель строки на WFD.cFileName(0)
        Do While Cont
            If c = 2& Then                 'пропускаем первые 2 итерации
Opchik:         WFD.dwReserved1 = lstrlen(lpStr) * 2 'пишем длину строки (в байтах) в WFD.dwReserved1 (=StrPtr(DirName)-4)
                If ListFiles = False Then
                    If (WFD.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) <> 0 Then ' Если это каталог
                        ReDim Preserve StrArray(cnt)
                        StrArray(cnt) = DirName
                        
                        cnt = cnt + 1
                    End If
                Else
                    If (WFD.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) = 0 Then ' Если это не каталог
                        ReDim Preserve StrArray(cnt)
                        StrArray(cnt) = DirName
                        
                        cnt = cnt + 1
                    End If
                End If
            Else
                If DirName <> "." And DirName <> ".." Then
                    c = 2
                    GoTo Opchik
                End If
                c = c + 1
            End If
            
            Cont = FindNextFileW(hSearch, WFD)
        Loop
        PutMem4 VarPtr(DirName), 0&       'сбрасываем указатель строки на 0
        Cont = FindClose(hSearch)
    End If
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
30.09.2023, 17:29

Создать файл, содержащий имена всех файлов системы, созданных в текущем месяце, имена пользователей, их создавших
Через командную строку необходимо: Создать файл, содержащий имена всех файлов системы, созданных в текущем месяце, имена пользователей,...

Функция поиска файлов, и вывод списка найденных (использую FindFirstFile, FindNextFile)
Друзья, возникла следующая сложность, написал функцию для поиска файлов(.txt) в текущей директории, название файлов нейзвестно, поэтому, с...

GetPixel не корректно определяет цвет
Добрый день! У меня стоит цель определять RGB пикселя в указанной курсором позиции в открытых изображениях. void...

OnEnterCollision не определяет имена и теги
Доброго времени суток, у меня возникла необходимость проверять на столкновения двух объектов, так вот я нашел функцию...

Переименование PDF-файлов в имена, берущиеся из содержимого этих файлов
Всем доброго времени суток!:) Подскажите, пожалуйста, как переименовать файл с расширением pdf, взяв сам текст для наименования файла из...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
89
Ответ Создать тему
Новые блоги и статьи
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
Сам себя обучал rest api
anaschu 02.07.2026
Педагогический лайфхак: Почему чистый REST API для ученика намного круче, чем готовые библиотеки Когда мы отказались от капризного JAR-файла AnyLogic и переписали код на стандартный HttpClient,. . .
rest api anylogic - выполнение модели на своём русском сайте
anaschu 02.07.2026
Как подружиться с AnyLogic Cloud API, победить провайдеров и развернуться Java-бэкенд в Docker на бесплатном хостинге: Двухдневный лог борьбы Всем привет! Хочу поделиться свежим (и довольно. . .
Где деньги лежат
kumehtar 02.07.2026
Это - японская подводная лодка I-52 (тип C2, кодовое имя Momi) вышла из Японии в марте 1944 года с миссией в оккупированную немцами Францию (Лорьян). Это была одна из «Янаги»-миссий по обмену. . .
Krabik для WoW 3.3.5a, многоязычный
AmbA 02.07.2026
Допилил бота, думаю что окончательно. Изменения: - добавлена многоязычность - добавлено снятие скриншотов - добавлено поддержание бафов хождения по воде (для жреца, дк и шамана) - и так, по. . .
Алиса нашла кучу ошибок компиляции и запуска в проекте, который без проблем компилировался и запускался)))
anaschu 30.06.2026
Я пока посмеюся, но завтра проверю. А вообще интерсно. Дал алисе файл, в котором точно нет ошибок компиляции и запуска, и попросил их найти. Нашла кучу))) Критические ошибки, мешающие компиляции и. . .
сукцессия 16. Общий обзор, в основном что бы другие ии поняли
anaschu 29.06.2026
# Передаточный документ: модель микоризной сукцессии (для нового чата) Этот документ предназначен для того, чтобы новый чат Claude мог продолжить работу без необходимости заново разбираться в. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru