CSVを取り込む その2

Dim FileN
Dim shTHIS As Worksheet
Dim tmp
Dim strBuf
Dim clm

'取り込むファイルをダイアログで選択、キャンセルで中断
FileN = Application.GetOpenFilename("CSVファイル,*.csv")
If FileN = False Then Exit Sub

'取り込み先のシートを指定
Set shTHIS = ThisWorkbook.Worksheets("シート名")
shTHIS.Cells.Clear

'対象ファイルのフィールド数を特定する
Open FileN For Input As #1
Line Input #1, strBuf
tmp = Split(strBuf, ",")

ReDim clm(UBound(tmp))
For i = 0 To UBound(tmp)
clm(i) = 2
Next i
Close #1

'外部データ取込機能で取り込む、貼り付け位置はDestinationで指定
With shTHIS.QueryTables.Add(Connection:="TEXT;" & FileN, Destination:=shTHIS.Range("$A$1"))
.TextFilePlatform = 932
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileCommaDelimiter = True
.TextFileColumnDataTypes = clm
.AdjustColumnWidth = False
.RefreshStyle = xlOverwriteCells
.Refresh
.Delete
End With

Open For Inputだと引用符(")の扱いで難しいのでQuertTablesで取り込むコード。
Excelの外部データ取り込み機能が基。

数値の自動変換対策に全て文字列とする。取り込む列全てに配列で指定しなければいけないので、汎用性を考えOpen For Inputで一行目だけ抜き取り列数を取得している。

↓以下説明とか

VBA CSV ファイルの読み込み (QueryTables.Add 関数を使う)

 .RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = False
.TextFileSpaceDelimiter = False

.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
  .Name = "" 'クエリとしてのテーブル名
.CommandType = 0
.FieldNames = True

 

ファイルを指定して開く

Dim FileName
FileName = Application.GetOpenFilename("CSVファイル,*.csv")
Workbooks.Open FileName

実行するとファイル選択のダイアログボックスが表示される。
選択し【開く】を押すとファイルのフルパスを文字列として取得する。
↑この例ではCSVのみ表示される。

GetOpenFilenameメソッドの説明。

GetOpenFilename FileFilter, FilterIndex, Title, ButtonText, MultiSelect

引数 必須 or 任意 説明
FileFilter 任意 文字列

表示するファイルの種類を指定する。
書式は"種類名,拡張子"
複数の拡張子を表示したい場合は拡張子をセミコロン( ; )で挟む。
複数の種類を設定する場合はカンマを挟み書式を繰り返す。
例)"ファイル,*.xlsx;*.csv,テキスト,*.txt"

FilterIndex 任意    
引数 必須 or 任意 説明
引数 必須 or 任意 説明
引数 必須 or 任意 説明

 XlGuessの自動判定とはExcelに表として認識された場合のみヘッダーとする。

 

CSVをExcelに取り込む

Dim tmp
Dim strBuf As String, strBuf1 As String
Dim i As Long
Dim LastLEN As Long
Dim shThis As Worksheet
Dim CSVpath As String

'シートとCSVのパスを指定
Set shThis = ThisWorkbook.Worksheets("")
CSVpath = ""

'取り込み先のシートをクリア
With shThis
.Cells.Clear

Open CSVpath For Input As #1
i = 1
Do Until EOF(1)
Line Input #1, strBuf

'セグメント内改行対策箇所
Do Until EOF(1)
If (Len(strBuf) - Len(Replace(strBuf, """", ""))) Mod 2 = 0 Then Exit Do
Line Input #1, strBuf1
strBuf = strBuf & strBuf1
Loop

'引用符削除
strBuf = Replace(strBuf, """,", ",")
strBuf = Replace(strBuf, ",""", ",")
strBuf = Replace(strBuf, """""", """")
If Left(strBuf, 1) = """" Then strBuf = Right(strBuf, Len(strBuf) - 1)
If Right(strBuf, 1) = """" Then strBuf = Left(strBuf, Len(strBuf) - 1)

'読み込んだ文字列を分割して配列に
tmp = Split(strBuf, ",")

'直前の配列と要素数が違えばメッセージ
If UBound(tmp) <> LastLEN And i > 1 Then msgbox "フィールド数が違う行があります。" & vbCrLf & "行:" & i
LastLEN = UBound(tmp)

'一行ずつ貼り付け
.Range(.Cells(i,1),.Cells(i,UBound(tmp)+1)) = tmp
i = i + 1
Loop
Close #1

End With

●問題点
文字の","が含まれていると、区切り文字の","を区別できないため分割される。
→カンマより左の引用符数をカウントして奇数なら文字の","と判別できる。が、数値の桁区切りの","には対応できない。
改行対策で改行を削除しているため実際のデータとは異なってくる。

配列を1要素ずつ指定すれば必要な列だけを抜き出すことも可能。
ただし要素を個別に張り付ける分、数が増えると処理時間が延びる。

 

先に表示形式を変えれば数値などの自動変換を防げる。

.Columns().NumberFormatLocal = "@" '文字列

※2018/4/24 修正
セグメント内改行対策コードの追加と引用符削除を手直し。

別のブックからシートを取り込む

Dim ws as worksheet
Dim wb as workbook

SN = "シート名"
BN = "ブック名"
Bpath = "ブックのPath"

'マクロ実行ブックに目的のシートがあれば消す
For Each ws In ThisWorkbook.Worksheets
If ws.Name = SN Then ws.Delete
Next ws

'目的のブックを開いているか判定
For Each WB In Workbooks
If WB.Name = BN Then fl = True
Next WB
'開いてたらコピーして取り込む、閉じてたら取り込んで閉じる
If fl Then
Workbooks(BN & ".xlsx").Sheets(SN).Copy Before:=ThisWorkbook.Sheets(1)
Else
Set WB = Workbooks.Open(Bpath & "\" & SN & ".xlsx")
WB.Sheets(SN).Move Before:=ThisWorkbook.Sheets(1)
End If

.

 

【RemoveDuplicates】重複削除する

・サンプル 

Range("A1:B" & .Cells(1, 1).End(xlDown).Row).RemoveDuplicates Columns:=Array(1, 2),Header:=xlYes

このサンプルはA1からの連続最終行を求め、A1:B最終行の範囲を指定。
重複判定Columnsに1列目(A列),2列目(B列)を指定しヘッダー(範囲内の1行目)は残す設定。

式 Range.RemoveDuplicates(Columns, Header)

引数 optional or required 説明
Columns 必須 バリアント型 重複判定する列のインデックスの配列を指定
Header 任意 XlYesNoGuess 1行目をヘッダーとするかどうか。XlGuessは自動判定

 XlGuessの自動判定とはExcelに表として認識された場合のみヘッダーとする。
使わないほうが無難。

Range.RemoveDuplicates メソッド (Excel)

【AdvancedFilter】テーブルからデータ抽出

テーブルから条件を指定して抽出する

Worksheets("").Range("").AdvancedFilter _'テーブルを指定
Action:=xlFilterCopy, _
CriteriaRange:=Worksheets("").Range(""), _'抽出条件がある範囲を指定
CopyToRange:=Worksheets("").Range(""), _'抽出先を指定
Unique:=False
End Sub
Action
必須
xlFilterCopy
(値は2)
リスト範囲とは他の場所に抽出データをコピーします
xlFilterInPlace
(値は1)
リスト範囲内にデータを抽出します
CriteriaRange
(省略可能)
Variant型の値を使用する 検索条件範囲を指定します。
省略すると、検索条件なしで抽出されます。
CopyToRange
(省略可能)
Variant型の値を使用する 引数 ActionがxlFilterCopyのときは、抽出された行のコピー先のセル範囲を指定します。
それ以外の場合、この引数は無視されます。
Unique
(省略可能)
True 検索条件に一致するレコードのうち、重複するレコードは無視されます。
FALSE 重複するレコードも含めて、検索条件に一致するレコードがすべて抽出されます。

 ・複数条件の指定方法

 横に並べるとand、縦に並べるとor になる

フィールド1 フィールド1 フィールド2
abc def ghi
123 456 789

この場合、or(and(フィールド1=abc,フィールド1=def,フィールド2=ghi),and(フィールド1=123,フィールド1=456,フィールド2=789))

が抽出される

Excel(エクセル)VBA入門:フィルタオプション(AdvancedFilter)でのデータ抽出