Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


19983 / 76732 ←次へ | 前へ→

【62174】Re:CSVファイルの読み込みについて
発言  kanabun  - 09/6/26(金) 11:53 -

引用なし
パスワード
   ▼困り猫 さん:

>無事、次の段階に進めそうです。

困り猫さんはどうも最初のサンプルコードの方法
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...) すれば、区切り記号を指定して
かつ、列のデータ型を指定して データベース風テキストが適切に
読めるのですから、それを使わない手はない、、
というのがぼくのスタンスですけど。

ではでは (^^
2 hits

【62143】CSVファイルの読み込みについて 困り猫 09/6/24(水) 16:23 質問
【62144】Re:CSVファイルの読み込みについて neptune 09/6/24(水) 16:54 発言
【62152】Re:CSVファイルの読み込みについて 困り猫 09/6/25(木) 11:07 質問
【62153】Re:CSVファイルの読み込みについて neptune 09/6/25(木) 11:20 回答
【62145】Re:CSVファイルの読み込みについて イブX 09/6/24(水) 17:35 発言
【62155】Re:CSVファイルの読み込みについて 困り猫 09/6/25(木) 12:54 お礼
【62157】Re:CSVファイルの読み込みについて kanabun 09/6/25(木) 14:06 発言
【62163】Re:CSVファイルの読み込みについて 困り猫 09/6/25(木) 16:28 お礼
【62174】Re:CSVファイルの読み込みについて kanabun 09/6/26(金) 11:53 発言
【62158】Re:CSVファイルの読み込みについて イブX 09/6/25(木) 14:45 発言
【62164】Re:CSVファイルの読み込みについて 困り猫 09/6/25(木) 16:34 お礼
【62146】Re:CSVファイルの読み込みについて kanabun 09/6/24(水) 20:31 発言
【62147】Re:CSVファイルの読み込みについて neptune 09/6/24(水) 20:48 発言
【62154】Re:CSVファイルの読み込みについて 困り猫 09/6/25(木) 11:45 お礼
【62148】Re:CSVファイルの読み込みについて 困り猫 09/6/24(水) 21:02 お礼

19983 / 76732 ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free