Workbooks.OpenText неправильно анализирует CSV-файлы Excel 2016

Я почти уверен, что это работало правильно в предыдущих версиях Excel.

Тестовый файл:

d/mm/yyyy hh:mm:ss
5/12/1999 6:01:12
30/11/2001 5:00:00

А разделителем между датой и временем является пробел (код ASCII 32).

  • Если файл сохранен как файл .txt, метод OpenText выполняет синтаксический анализ правильно.

  • Если файл сохранен как файл .csv, метод OpenText вообще не работает.

  • Если пробелы заменены запятыми, а файл сохранен как файл .csv, метод OpenText разделит строки на два столбца, но не будет правильно интерпретировать строку даты.

Мои региональные настройки Windows — mdy, а моя версия Excel — 2016.


Option Explicit
Sub foo()
    Dim WB As Workbook
    Dim sFN As String
    Dim FD As FileDialog

Set FD = Application.FileDialog(msoFileDialogFilePicker)

With FD
    .AllowMultiSelect = False
    .Filters.Add "Text or CSV", "*.txt, *.csv", 1
    .Show
    sFN = .SelectedItems(1)
End With

Workbooks.OpenText Filename:=sFN, DataType:=xlDelimited, origin:=437, _
        TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=True, Tab:=False, _
        Semicolon:=False, Comma:=False, Space:=True, Other:=False, _
        FieldInfo:=Array(Array(1, xlDMYFormat), Array(2, xlGeneralFormat))


Set WB = ActiveWorkbook

End Sub


person Ron Rosenfeld    schedule 13.02.2017    source источник
comment
Не зная, какие у вас есть другие столбцы, кажется, что вы можете просто прочитать дату и время как один столбец даты. Похоже, именно это Excel и делает с CSV-файлом.   -  person ThunderFrame    schedule 13.02.2017
comment
.Filters.Add "Text or CSV", "*.txt, *.csv", 1 Хм, нет, CSV и Text на самом деле не одно и то же для Excel. Мало того, что настройки разделителя очень специфичны для CSV и не устанавливаются с помощью параметра в Workbooks.OpenText, также обработка юникода является особым случаем для CSV и заметно отличается от Text.   -  person Axel Richter    schedule 13.02.2017
comment
@ThunderFrame Это не сработает без изменения региональных настроек Windows.   -  person Ron Rosenfeld    schedule 13.02.2017
comment
@AxelRichter Я думал, что это работало в 2007 году, но у меня больше нет этого для тестирования. Кроме того, в собственном диалоговом окне открытия файла Excel текстовые файлы отображаются как Text Files (*.prn,*.txt,*.csv). В 2016 VBA кажется, что он терпит неудачу только в том случае, если суффикс файла равен .csv. Другие суффиксы, или даже файлы без суффикса, успешны.   -  person Ron Rosenfeld    schedule 13.02.2017
comment
@Ron Rosenfeld: также не работает с Excel 2007. Хотите верьте, хотите нет, но CSV не просто текст для Excel. Есть даже недокументированный параметр sep= в начале файла для изменения ожидаемого разделителя. См. также en.wikipedia.org/wiki/.   -  person Axel Richter    schedule 13.02.2017
comment
@AxelRichter Спасибо за тестирование.   -  person Ron Rosenfeld    schedule 13.02.2017


Ответы (4)


Спасибо всем за предложения. Среди возможных решений я решил для своих целей удалить суффикс *.csv из файла. Это работает и может быть адаптировано. Метод QueryTable также будет работать вместе с предостережениями, опубликованными Акселем.

Вот код, который работает для моего метода, если кому интересно.


Option Explicit
Sub foo()
    Dim WB As Workbook, wbCSV As Workbook, swbCSV As String
    Dim sFN As String, sCopyFN
    Dim FD As FileDialog

Set WB = ThisWorkbook
Set FD = Application.FileDialog(msoFileDialogFilePicker)

With FD
    .AllowMultiSelect = False
    .Filters.Add "Text or CSV", "*.txt, *.csv", 1
    .Show
    sFN = .SelectedItems(1)
End With

'If CSV, remove suffix
sCopyFN = ""
If sFN Like "*.csv" Then
    sCopyFN = Left(sFN, Len(sFN) - 4)
    FileCopy sFN, sCopyFN
    sFN = sCopyFN
End If

Workbooks.OpenText Filename:=sFN, DataType:=xlDelimited, origin:=437, _
        TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=True, Tab:=False, _
        Semicolon:=False, Comma:=False, Space:=True, Other:=False, _
        FieldInfo:=Array(Array(1, xlDMYFormat), Array(2, xlGeneralFormat))

Set wbCSV = ActiveWorkbook

'Get path as string since it will not be available after closing the file
swbCSV = wbCSV.FullName

'Move the data into this workbook
Dim rCopy As Range, rDest As Range

With WB.Worksheets("sheet1")
    Set rDest = .Cells(.Rows.Count, 1).End(xlUp)
End With
Set rCopy = wbCSV.Sheets(1).UsedRange

rCopy.Copy rDest

'must close the file before deleting it
wbCSV.Close False
Kill swbCSV

End Sub

person Ron Rosenfeld    schedule 13.02.2017

Похоже, что это может быть та же проблема, обсуждаемая в этой теме:

Открытие файлов CSV в Excel 2016

Файлы CSV представляют собой файлы со значениями, разделенными символами, а не запятыми. Более чем в половине стран мира разделителем является точка с запятой (;), а не запятая (,).

Excel 2016 правильно учитывает региональные настройки Windows и использует указанный символ «разделитель списка».

Одним из решений является изменение региональных настроек для атрибута «Разделитель списка» на символ, который вы хотите, чтобы Excel использовал по умолчанию, например. запятая (,)

Это можно изменить в:

Панель управления/Регион/Дополнительные настройки/Разделитель списка:

person J. Garth    schedule 13.02.2017
comment
Эта проблема не связана с методом OpenText и не связана с ним. - person Ron Rosenfeld; 13.02.2017

CSV и Text на самом деле не одно и то же для Excel. Дело не только в том, что настройки разделителя очень специфичны для CSV и не устанавливаются с помощью параметра в Workbooks.OpenText. Также другие параметры, такие как типы полей (FieldInfo), также не будут учитываться при открытии файлов CSV. А также обработка юникода является особым случаем для CSV и значительно отличается от Text.

Вы можете попробовать использовать QueryTables так:

Sub foo1()
    Dim WB As Workbook
    Dim sFN As String
    Dim FD As FileDialog

Set FD = Application.FileDialog(msoFileDialogFilePicker)

With FD
    .AllowMultiSelect = False
    .Filters.Add "Text or CSV", "*.txt, *.csv", 1
    .Show
    sFN = .SelectedItems(1)
End With

Set WB = Workbooks.Add

With WB.Worksheets(1).QueryTables.Add(Connection:= _
    "TEXT;" & sFN & "", Destination:=Range("$A$1"))
    .Name = "test"
    .TextFileParseType = xlDelimited
    .TextFileTextQualifier = xlTextQualifierDoubleQuote
    .TextFileConsecutiveDelimiter = True
    .TextFileTabDelimiter = False
    .TextFileSemicolonDelimiter = False
    .TextFileCommaDelimiter = False
    .TextFileSpaceDelimiter = True
    .TextFileColumnDataTypes = Array(xlDMYFormat, xlGeneralFormat)
    .Refresh BackgroundQuery:=False
End With

End Sub

Но при использовании QueryTables, конечно, вы должны быть осторожны, не добавляя их несколько раз без необходимости, а вместо этого обновляя их или сначала удаляя их, а затем добавляя снова.

person Axel Richter    schedule 13.02.2017
comment
Я надеялся избежать использования метода Query Tables. - person Ron Rosenfeld; 13.02.2017

Объединение моих экспериментов и ответа Акселя Рихтера https://stackoverflow.com/a/42198852/2026637 с ответом dwirony на связанный вопрос https://stackoverflow.com/a/55166268/2026637:

  1. При импорте файла CSV с расширением .csv с помощью OpenText или Open все даты рассматриваются как формат MDY (американский).
  2. OpenText игнорирует все параметры формата с файлом CSV, имеющим расширение .csv.
  3. В файле CSV, имеющем расширение .txt и использующем параметр xlDelimited, OpenText учитывает параметр FileInfo, но номера столбцов игнорируются, поэтому элемент массива должен присутствовать для каждого столбца, начиная с 1 и до всех столбцов с нестандартным значением. описаны форматы.

Разочаровывает то, что пользовательский интерфейс работает правильно (включая по умолчанию региональный формат даты), но интерфейс VBA имеет эти проблемы.

Проблемы присутствуют как в Excel 2013, так и в Excel 2016.

person grahamj42    schedule 12.09.2020
comment
Я согласен. Я по умолчанию использовал Power Query для импорта. Неважно, .txt это или .csv (или .???). Можно сообщить PQ о входящем формате даты, и он обработает его правильно, если вы не измените запрос. Освежить тоже просто. - person Ron Rosenfeld; 12.09.2020