|
▼困り猫 さん:
>無事、次の段階に進めそうです。
困り猫さんはどうも最初のサンプルコードの方法
Input#ステートメントにこだわりをお持ちのようですが、
Input#文を使っての読み込みは今回のCSVファイルの形式に
は不適当なことを具体例で検証してみたいと思います。
まず、同じシート上にある同じデータを
Print# と
Write# を使って出力してみます。
データは簡単のために、(Sheetではなく)
以下のように Array関数で与えるものとします。
>----------------- Openステートメント関係による 入出力テスト
Option Explicit
'--------- テストで共通に使用する2つの形式のCSVファイルの宣言
Private Const myFileP = "D:\(Data)\test_Print.csv"
Private Const myFileW = "D:\(Data)\test_Write.csv"
Sub test_Print() '▲Print#ステートメントで出力
Dim Arry
Arry = Array("青木", 1, 3, 8, 0, "1|5", 9, Date)
Dim io As Integer
io = FreeFile()
Open myFileP For Output As io
Print #io, Join(Arry, ",")
Close io
End Sub
Sub Test_Write() '▲Write#ステートメントで出力
Dim Arry
Arry = Array("青木", 1, 3, 8, 0, "1|5", 9, Date)
Dim io As Integer
Dim j As Long
io = FreeFile()
Open myFileW For Output As io
For j = 0 To UBound(Arry) - 1
Write #io, Arry(j);
Next
Write #io, Arry(UBound(Arry))
Close io
End Sub
出力結果ですが、▲Print# 文で出力したものはこうなります。
青木,1,3,8,0,1|5,9,2009/06/26
これは 困り猫さんが読み込もうとしているCSVファイルと(たぶん)
同じ形式のデータレイアウトです。
またこの形式は、Excelメニューから
「名前を付けて保存」[ファイルの種類:CSV形式]で、
xlCSV出力したときのファイル形式と(このばあいは)
同じです。↓
青木,1,3,8,0,1|5,9,2009/6/26
Print #文は、いわば文章をそのままのかたちでファイルに
書き込むのに適しています。逆に、今回のように 1行内で
データを区切る必要があるときは、自前で区切り記号を
挿入する必要があります。
一方、▲Write#文で出力した結果はこうなります。
"青木",1,3,8,0,"1|5",9,#2009-06-26#
Write#文は、Print# 文と異なり、ファイルにデータを書き
込むときにデータ項目の間にカンマ (,) を挿入します。
文字列データは、ダブルクォート("")で囲んで出力されます。
日付データは、#で囲んで出力されます。
さて、この2つの形式のCSVファイルの読み込みですが、
ヘルプの「Print # ステートメント」の解説にあるように、
> 通常、Print # ステートメントを使用して書き込んだ
> データは、Line Input # ステートメントまたは
> Input 関数を使用して読み込みます。
一方、ヘルプの「Write # ステートメント」の解説にあるように、
> Write # ステートメントを使用して書き込んだデータは、
> Input # ステートメントで読み込みます。
同じくInput#ステートメントの「メモ」にあるように、
> Input # ステートメントを使用してファイルから変数へデータを
> 正しく読み込むことができるように、データをファイルに書き込む
> 場合は、Print # ステートメントではなく、必ず Write # ステー
> トメントを使用してください。
そこで、以下、2つのCSVファイルの読み込みの実験です。
まず、Print#文で出力したCSVファイルのほうから。
'▼Print#で出力したCSVを読む (その1: Line Input#)
Sub test_LineInput()
Dim io As Integer
Dim L&
Dim sLine$, Arry As Variant
io = FreeFile()
Open myFileP For Input As io
L = Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
Do Until EOF(io)
Line Input #io, sLine
L = L + 1
Arry = Split(sLine, ",")
Cells(L, 1).Resize(, UBound(Arry) + 1).Value = Arry
Loop
Close io
End Sub
sheet への出力結果は以下のイメージとなります。
>---------------------------------------------------------
A | B | C | D | E | F | G | H
青木 '1 '3 '8 '0 1|5 '9 2009/6/26
↑文字列
>---------------------------------------------------------
上のイメージ図で 数値の前のアポストロフィ―(') は
セルの左上コーナーのエラーインジケータを表しています。
つまり、この方法で読み込むと、全てのデータが「文字列」
として読み込まれていることを示しています。
Print#文で出力したCSVを読み込むにはもう一つの方法があります。
この方法はテキストファイルを高速に読み込むことができますが、
配列を使用していますのでコードがやや長くなります。
'▼Print#で出力したCSVを読む (その2: Get#)
Sub test_Get()
Dim io As Integer
Dim Buf() As Byte, Arry As Variant
Dim i&, j&, y&, x&
Dim v
Dim outArry
io = FreeFile()
Open myFileP For Binary As io
ReDim Buf(1 To LOF(io))
Get #io, , Buf '全文一括読み込み(ShiftJIS)
Close io
' ↓ Unicodeに変換し行に分割
Arry = Split(StrConv(Buf, vbUnicode), vbCrLf)
y = UBound(Arry) - 1 '最終行
x = UBound(Split(Arry(0), ",")) '最終列
ReDim outArry(y, x)
For i = 0 To y
v = Split(Arry(0), ",") '一行を列に分割
For j = 0 To x
outArry(i, j) = v(j) '出力用配列に格納
Next
Next
' シートに吐き出す
ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Offset(2) _
.Resize(y + 1, x + 1).Value = outArry
End Sub
'
Get#ステートメントによる 読み込みの
sheet への出力結果は以下のイメージとなります。
>---------------------------------------------------------
A | B | C | D | E | F | G | H
青木 1 3 8 0 1|5 9 2009/6/26
>---------------------------------------------------------
こんどは文字列は左詰め、数値データは右詰めに配置され、
元のシートデータを正しく読み込むことができました。
CSVファイル形式が(Print#文で出力された)文字列データが
("")で囲まれていない、また日付データが(# #)で囲まれていない
テキストのときは、このGet#による方法が適当と思われます。
他方、文字列データが("")で囲まれていたり、日付型データが
(##)で囲まれているような Write#文で出力した データ型情報付き
CSVテキストを読むときは、ヘルプの解説に明らかなように、
「Input#文」で読み込むのがベターということになります。↓
'▼Write#で出力したCSVを読む (Input#)
Sub test_Input()
Dim io As Integer
Dim Arry As Variant
Dim j&, x&, L&
io = FreeFile()
Open myFileW For Input As io
x = 8 'testのため 列数 決め打ち
ReDim Arry(1 To x)
L = Cells(Rows.Count, 1).End(xlUp).Offset(1).Row
Do Until EOF(io)
For j = 1 To x
Input #io, Arry(j)
Next
L = L + 1
Cells(L, 1).Resize(, x).Value = Arry
Loop
Close io
End Sub
Write#文で出力したCSVテキストを Input#文で項目ごとに
読んだ結果(シートに貼り付けた結果)は以下のようになります。
>---------------------------------------------------------
A | B | C | D | E | F | G | H
青木 1 3 8 0 1|5 9 2009/6/26
>---------------------------------------------------------
データ型の情報(文字列、日付、エラー値、論理値など)が
テキスト内に付随しているときは、(少々時間はかかりますが)
Input#文を使って読み込むとデータの誤変換、自動削除が発生し
ません。
ただ、ファイルにより列数が不定の場合は、何らかの方法で
ファイルの先頭行を 先読みして 列数を把握しておく必要がありますが。
大変ながくなりましたが、以上のコメントは Openステートメントを
使うとしたら、という仮定でのお話です。
文字列データが ("")で括られていても、Excelの一般機能である
テキストファイルウィザードをマクロ化(Workbooks>OpenText
ActiveSheet.QueryTables.Add...) すれば、区切り記号を指定して
かつ、列のデータ型を指定して データベース風テキストが適切に
読めるのですから、それを使わない手はない、、
というのがぼくのスタンスですけど。
ではでは (^^
|
|