Excel VBA質問箱 IV

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

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


1573 / 13645 ツリー ←次へ | 前へ→

【73400】テキストファイルのデータをのセルに転記したい es 13/1/5(土) 14:58 質問[未読]
【73401】Re:テキストファイルのデータをのセルに転... UO3 13/1/5(土) 15:32 発言[未読]
【73402】Re:テキストファイルのデータをのセルに転... es 13/1/5(土) 15:47 発言[未読]
【73403】Re:テキストファイルのデータをのセルに転... UO3 13/1/5(土) 15:57 発言[未読]
【73405】Re:テキストファイルのデータをのセルに転... es 13/1/5(土) 16:34 質問[未読]
【73407】Re:テキストファイルのデータをのセルに転... UO3 13/1/5(土) 17:35 発言[未読]
【73408】Re:テキストファイルのデータをのセルに転... es 13/1/5(土) 18:22 お礼[未読]
【73423】Re:テキストファイルのデータをのセルに転... kanabun 13/1/6(日) 20:40 発言[未読]
【73424】Re:テキストファイルのデータをのセルに転... UO3 13/1/7(月) 6:29 発言[未読]
【73430】Re:テキストファイルのデータをのセルに転... es 13/1/8(火) 20:53 お礼[未読]
【73410】Re:テキストファイルのデータをのセルに転... es 13/1/5(土) 20:04 質問[未読]
【73411】Re:テキストファイルのデータをのセルに転... UO3 13/1/5(土) 20:20 発言[未読]
【73412】Re:テキストファイルのデータをのセルに転... es 13/1/5(土) 20:29 お礼[未読]
【73404】Re:テキストファイルのデータをのセルに転... UO3 13/1/5(土) 16:03 発言[未読]

【73400】テキストファイルのデータをのセルに転記...
質問  es  - 13/1/5(土) 14:58 -

引用なし
パスワード
   オデッセイコミュニケーションのテキストを見ながらマクロを組んでみましたが、
うまくいきません。

やりたいこと あるフォルダにテキストファイルが複数あり、
その中身を1ファイル→エクセルの1シートに転記したい。
テキストファイルの中身はメール本文を保存したもので、
データが改行で区切られている。
テキストの1行目 → シートの1行目1列目のセル
テキストの2行目 → シートの2行目1列目のセル
というように、書き込みをしたい。

下記のようにマクロを書いてみたのですが、
cells(1,1)にすべてのデータが格納されてしまいます。
1行→1セルというように書き込むにはどうすればよいのでしょうか。
ご指導のほど、よろしくお願いいたします。


Sub ファイル読み込み1()

  Dim myfilenames As Variant
  Dim i As Integer
  Dim temp As String
  
  
  myfilenames = Application.GetOpenFilename(MultiSelect:=True)
  
  If IsArray(myfilenames) = True Then
    
    For i = 1 To UBound(myfilenames)
    
    temp = Space(FileLen(myfilenames(i)))
    
    Open myfilenames(i) For Binary As #i
    
      Get #i, , temp
      
    Close #i
      
    ThisWorkbook.Worksheets(i).Cells(1, 1) = temp
  
    Next i
    
  End If

以上

【73401】Re:テキストファイルのデータをのセルに...
発言  UO3  - 13/1/5(土) 15:32 -

引用なし
パスワード
   ▼es さん:

回答案の前に確認です。
アップされたコードは、複数のテキストファイルを選択(1つでもOK)
選択されたファイルを順番に1つずつ開いて処理していますね。
その複数のファイルを順に読むためのインデックス変数として i があります。
で、1つのファイルを読み込んだ後、そこ i を行番号として 読み込んだ temp を転記。

これは意図通りですか?
おそらく選択するファイルは1つだけ。
で、そのファイルの各行をマクロブックのシートの1行目、2行目、・・・と
転記していきたいと言うことなのではないですか?

【73402】Re:テキストファイルのデータをのセルに...
発言  es  - 13/1/5(土) 15:47 -

引用なし
パスワード
   早速ありがとうございます。
sheetのインデックスをiにしているので、
このマクロを実行すると、
たとえば2つのファイルを選択すると、
1つ目に開けたファイルのデータすべてがsheet1のセルA1に、
2つ目に開けたファイルのデータすべてがsheet2にセルA1に
格納されてしまいます。
やりたいことは、1つのセルにすべてのデータが入るのではなく、
1つ目に開けたファイルのデータを、
sheet1のA1セルに1行目のデータ、
A2セルに2行目のデータ。
2つ目に開けたファイルのデータを
sheet2に、
という風に転記したいです。


これで確認の答えになっていますか?

【73403】Re:テキストファイルのデータをのセルに...
発言  UO3  - 13/1/5(土) 15:57 -

引用なし
パスワード
   ▼es さん:

とりあえず現行の複数ファイル選択ベースです。
シートもファイル毎に、分けています。

Sub ファイル読み込み2()

  Dim myfilenames As Variant
  Dim i As Integer
  Dim temp As String
 
  Dim x As Long
  Dim d As Variant
  Dim dx As Variant
 
  myfilenames = Application.GetOpenFilename(MultiSelect:=True)
 
  If IsArray(myfilenames) = True Then
    If UBound(myfilenames) > ThisWorkbook.Worksheets.Count Then
      MsgBox "選択されたファイル数が転記用シート数を超えています"
    Else
    
     For i = 1 To UBound(myfilenames)
   
       temp = Space(FileLen(myfilenames(i)))
     
       Open myfilenames(i) For Binary As #i
     
         Get #i, , temp
      
       Close #i
      
        d = Split(temp, vbCrLf)
        x = 0
        For Each dx In d
          x = x + 1
          ThisWorkbook.Worksheets(i).Cells(x, "A").Value = dx
        Next
  
     Next i
    
    End If
    
  End If

  
End Sub

【73404】Re:テキストファイルのデータをのセルに...
発言  UO3  - 13/1/5(土) 16:03 -

引用なし
パスワード
   ▼es さん:

複数ファイル --> 複数シート の件了解です。
であればアップ済みのコードでいけると思いますが、以下は
シート転記時のループをなくしたバージョンです。

Sub ファイル読み込み3()

  Dim myfilenames As Variant
  Dim i As Integer
  Dim temp As String
 
  Dim d As Variant
 
  myfilenames = Application.GetOpenFilename(MultiSelect:=True)
 
  If IsArray(myfilenames) = True Then
    If UBound(myfilenames) > ThisWorkbook.Worksheets.Count Then
      MsgBox "選択されたファイル数が転記用シート数を超えています"
    Else
    
     For i = 1 To UBound(myfilenames)
   
       temp = Space(FileLen(myfilenames(i)))
     
       Open myfilenames(i) For Binary As #i
     
         Get #i, , temp
      
       Close #i
      
       With ThisWorkbook.Worksheets(i)
         d = Split(temp, vbCrLf)
        .Cells.ClearContents
        .Cells(1, "A").Resize(UBound(d)).Value = _
          WorksheetFunction.Transpose(d)
       End With
      
     Next i
    
    End If
    
  End If

  
End Sub

【73405】Re:テキストファイルのデータをのセルに...
質問  es  - 13/1/5(土) 16:34 -

引用なし
パスワード
   ▼UO3 さん:
早速ありがとうございます!

splitでデータを一次元配列に変換して、
その配列のindex1番目を、
シートのA列の1行目に、
index2番目を2行目にと順番に代入していくということですね。

一つ質問ですが、
dが配列ならそのindex番号としてd(x)と記述しなくてよいのでしょうか。

【73407】Re:テキストファイルのデータをのセルに...
発言  UO3  - 13/1/5(土) 17:35 -

引用なし
パスワード
   ▼es さん:

配列からのデータの取り出しは、配列内の要素番号(インデックス)を与えて
For/Next で取り出す方法以外に、For Each/Next で配列内の要素を、Variant型変数に
あるだけ取り出す方法があります。

以下参考です。

Sub Test1()
  Dim d(1 To 3)
  Dim i As Long
  
  d(1) = "A"
  d(2) = "B"
  d(3) = "C"
  
  For i = 1 To UBound(d)
    MsgBox d(i)
  Next
  
End Sub

Sub Test2()
  Dim d(1 To 3)
  Dim dx As Variant
  
  d(1) = "A"
  d(2) = "B"
  d(3) = "C"
  
  For Each dx In d
    MsgBox dx
  Next
  
End Sub

【73408】Re:テキストファイルのデータをのセルに...
お礼  es  - 13/1/5(土) 18:22 -

引用なし
パスワード
   ▼UO3 さん:
ありがとうございます。

そういう記述の仕方もあるのですね。
丁寧に参考記述もありがとうございました。

ほんとに短時間でレスいただけたことにびっくりです。
私はほんとにビギナーなので、
素直に尊敬の念を抱きます。

U03さんみたいにエキスパートに一歩でも近づけるよう頑張ります!

【73410】Re:テキストファイルのデータをのセルに...
質問  es  - 13/1/5(土) 20:04 -

引用なし
パスワード
   ▼UO3 さん:
一旦、お礼を申し上げた後にもう一度質問ですみません。
参考の例をもとに、
配列のインデックスを使った記述もつくってみたのですが、
うまくいきません。

Sub ファイル読み込み4_3()

  Dim myfilenames As Variant
  Dim i As Integer
  Dim temp As String

  Dim d As Variant
  Dim j As Long

  myfilenames = Application.GetOpenFilename(MultiSelect:=True)

  If IsArray(myfilenames) = True Then
    If UBound(myfilenames) > ThisWorkbook.Worksheets.Count Then
      MsgBox "選択されたファイル数が転記用シート数を超えています"
    Else
  
     For i = 1 To UBound(myfilenames)
 
       temp = Space(FileLen(myfilenames(i)))
  
       Open myfilenames(i) For Binary As #i
  
         Get #i, , temp
   
       Close #i
   
        d = Split(temp, vbCrLf)
        j = 1
        
        For j = 1 To UBound(d)
          
          ThisWorkbook.Worksheets(i).Cells(j, "A").Value = d(j)
          j = j + 1
          
        Next j
        
 
     Next i
  
    End If
  
  End If

 
End Sub

これを実行すると
なぜか、1行置きにデータが転記され、
1行空白のセルができてしまいます。

ウォッチ式で
ThisWorkbook.Worksheets(i).Cells(j, "A").Value = d(j)
の右辺と左辺を追ってみていくと、
d(j)には値が格納されているにも関わらず、
左辺には1行ずつにempty値が代入されていきます。

なぜでしょうか。
またお手すきのとき教えてください。

【73411】Re:テキストファイルのデータをのセルに...
発言  UO3  - 13/1/5(土) 20:20 -

引用なし
パスワード
   ▼es さん:

こんばんは
参考でアップしたTest1をよく見ていただきたいのですが、For/Next の中で
インデックス x は 加算していませんよね。
Next で自動的に1アップされます。

ですから、j = j + 1 は不要です。

【73412】Re:テキストファイルのデータをのセルに...
お礼  es  - 13/1/5(土) 20:29 -

引用なし
パスワード
   ▼UO3 さん:
ありがとうございます!

ほんとだ、初歩的なミス。
for/next文は自動的に変数が加算されるんですよね。

ありがとうございました。

【73423】Re:テキストファイルのデータをのセルに...
発言  kanabun  - 13/1/6(日) 20:40 -

引用なし
パスワード
   ▼es さん:
>▼UO3 さん:

解決後ですが、今しがた気づいたことで失礼します。

>    temp = Space(FileLen(myfilenames(i)))
>     
>    Open myfilenames(i) For Binary As #i
>     
>      Get #i, , temp
>      
>    Close #i
>      
>    d = Split(temp, vbCrLf)

ですが、ちょっとまずいと思います。
例として、
---------------------------------------
ABCDE<改行>
あいうえお<改行>
---------------------------------------
のような2行のテキストファイルを例として考えてみます。

まず、
>    temp = Space(FileLen(myfilenames(i)))
により、このファイルの長さの分だけのスペースが 文字列型変数temp
にセットされます。ファイルの長さ(FileLen)はバイト長で表示されます。
例に挙げたテキストファイルでいえば このファイルの長さすなわちバイト長は
 1行目が 5バイト+2
 2行目が 10バイト+2 (+2 は改行コード分)
で 合計 19バイトです。
ですので、上の一行は 今回の例では
   temp = Space$(19)
ということになります。
で、(ここが重要なのですが)Space$(19) ということは 19個のスペース
を確保という意味で、19バイト確保ではない----これが第1のポイントです。
Windowsのテキストファイルは 文字コードが ShiftJIS ですが、VBA内では
文字コードは Unicode で処理されます。
どういうことかというと、
ファイル上の "A" は1バイトですが Unicode に変換されると "A" は2バイト
になるということです。ファイル上の1バイトが2バイトになるということです。
ですから、バイト単位でスペースを用意すると考えると、
半角英数字のばあいは "A" という1バイトが VBA上で "A"という2バイトに変換
されるから、問題ないのですが、
全角コードのばあい たとえば「あ」という1文字2バイト が Unicode でも文字
数・バイト数ともに変わらなく 1文字2バイト のままなので、上のテキストファ
イルを
   temp = Space$(19)
で19文字分のスペースを用意して読み込むと、「あいうえお」の分だけスペース
が余ってきます。

テキストファイル    メモリ (Unicode)
char   バイト    char バイト
-------- ----     ---- -------
A    1       A   2
B    1       B   2
C    1       C   2
D    1       D   2
E    1       E   2
<改行>  2       <改行> 4 
あ    2       あ   2  
い    2       い   2 
う    2       う   2 
え    2       え   2 
お    2       お   2 
<改行>  2       <改行> 4
 
上の表から分かる通り、Unicodeとして必要なのは19文字38バイトではなく、
「14文字 28バイト」なのです。
Unicode変換するのに必要な長さは バイト長ではなく、実は文字長なのです。
ところが、ファイルの長さ情報は 文字数ではなく、FileLenで得られるような
バイト長しかありませんから、そもそも String型の変数をスペースで文字数分
初期化しておいて、そこにUnicode変換した文字を埋め込むという方法は
テキストが2バイトコードを含むときには うまくいきません。(用意されたス
ペースは必要な数より漢字の個数分、余ってきます)


あと、もうひとつ。

>    d = Split(temp, vbCrLf)

>    .Cells(1, "A").Resize(UBound(d)).Value = _
          WorksheetFunction.Transpose(d)
ですが、
たとえば、
"ABCDE▼1234▼あいうえお▼"
という文字列を Split(temp, "▼") で 分割しますと、
添字は (0) から始まりますから、

(0) "ABCDE"
(1) "1234"
(2) "あいうえお"
(3) ""

となります。UBbound(d) は 3 なのです。 もっとも UBound(d) である (3)
は 最後の改行コード▼ のさらにあとで、Empty ですから、これは シートに
貼り付ける必要はないので、 (0)〜 (2) までの 3行を貼り付ける、というこ
とになるので、
> .Resize(UBound(d))
というのは 結果オーライ ではあるのですが。

なので、文字列型変数にGet# はしなくて、バイト型配列に Get# してから
あとで Unicode文字列に変換します。こうすれば、お尻に余分なスペースが
つくことはありませんし、スピードもずっと速いです。

  Dim buf() As Byte
  Dim Filename As String
  Dim io As Integer
  Dim strArry As Variant
  Dim i As Long
  
  io = FreeFile()
  Open Filename For Binary As io
   ReDim buf(1 To LOF(io))
   Get io, , buf
  Close io
  strArry = Split(StrConv(buf, vbUnicode), vbCrLf)

  For i = 0 To UBound(strArry) - 1
    Debug.Print strArry(i)
  Next

【73424】Re:テキストファイルのデータをのセルに...
発言  UO3  - 13/1/7(月) 6:29 -

引用なし
パスワード
   ▼kanabun さん:

お世話様です。
ご教示ありがとうございました。

アップされたコード全体をよく読まず、値を分解するところだけを追加してしまいした。
注意力散漫でした。

勉強になります。
本年もよろしくお願いします。

【73430】Re:テキストファイルのデータをのセルに...
お礼  es  - 13/1/8(火) 20:53 -

引用なし
パスワード
   ▼kanabun さん:
メール確認していなくて、お礼遅くなりました。
詳細にありがとうございます。
私の知識では
ゆっくりゆっくり読み解かないとすぐには理解できないのですが^_^;
とにかくバグる可能性があるということですね。
ありがとうございます!
またよろしくお願いいたします。

>▼es さん:
>>▼UO3 さん:
>
>解決後ですが、今しがた気づいたことで失礼します。
>
>>    temp = Space(FileLen(myfilenames(i)))
>>     
>>    Open myfilenames(i) For Binary As #i
>>     
>>      Get #i, , temp
>>      
>>    Close #i
>>      
>>    d = Split(temp, vbCrLf)
>
>ですが、ちょっとまずいと思います。
>例として、
>---------------------------------------
>ABCDE<改行>
>あいうえお<改行>
>---------------------------------------
>のような2行のテキストファイルを例として考えてみます。
>
>まず、
>>    temp = Space(FileLen(myfilenames(i)))
>により、このファイルの長さの分だけのスペースが 文字列型変数temp
>にセットされます。ファイルの長さ(FileLen)はバイト長で表示されます。
>例に挙げたテキストファイルでいえば このファイルの長さすなわちバイト長は
> 1行目が 5バイト+2
> 2行目が 10バイト+2 (+2 は改行コード分)
>で 合計 19バイトです。
>ですので、上の一行は 今回の例では
>   temp = Space$(19)
>ということになります。
>で、(ここが重要なのですが)Space$(19) ということは 19個のスペース
>を確保という意味で、19バイト確保ではない----これが第1のポイントです。
>Windowsのテキストファイルは 文字コードが ShiftJIS ですが、VBA内では
>文字コードは Unicode で処理されます。
>どういうことかというと、
>ファイル上の "A" は1バイトですが Unicode に変換されると "A" は2バイト
>になるということです。ファイル上の1バイトが2バイトになるということです。
>ですから、バイト単位でスペースを用意すると考えると、
>半角英数字のばあいは "A" という1バイトが VBA上で "A"という2バイトに変換
>されるから、問題ないのですが、
>全角コードのばあい たとえば「あ」という1文字2バイト が Unicode でも文字
>数・バイト数ともに変わらなく 1文字2バイト のままなので、上のテキストファ
>イルを
>   temp = Space$(19)
>で19文字分のスペースを用意して読み込むと、「あいうえお」の分だけスペース
>が余ってきます。
>
> テキストファイル    メモリ (Unicode)
>char   バイト    char バイト
>-------- ----     ---- -------
>A    1       A   2
>B    1       B   2
>C    1       C   2
>D    1       D   2
>E    1       E   2
><改行>  2       <改行> 4 
>あ    2       あ   2  
>い    2       い   2 
>う    2       う   2 
>え    2       え   2 
>お    2       お   2 
><改行>  2       <改行> 4
> 
>上の表から分かる通り、Unicodeとして必要なのは19文字38バイトではなく、
>「14文字 28バイト」なのです。
>Unicode変換するのに必要な長さは バイト長ではなく、実は文字長なのです。
>ところが、ファイルの長さ情報は 文字数ではなく、FileLenで得られるような
>バイト長しかありませんから、そもそも String型の変数をスペースで文字数分
>初期化しておいて、そこにUnicode変換した文字を埋め込むという方法は
>テキストが2バイトコードを含むときには うまくいきません。(用意されたス
>ペースは必要な数より漢字の個数分、余ってきます)
>
>
>あと、もうひとつ。
>
>>    d = Split(temp, vbCrLf)
>
>>    .Cells(1, "A").Resize(UBound(d)).Value = _
>          WorksheetFunction.Transpose(d)
>ですが、
>たとえば、
>"ABCDE▼1234▼あいうえお▼"
>という文字列を Split(temp, "▼") で 分割しますと、
>添字は (0) から始まりますから、
>
>(0) "ABCDE"
>(1) "1234"
>(2) "あいうえお"
>(3) ""
>
>となります。UBbound(d) は 3 なのです。 もっとも UBound(d) である (3)
>は 最後の改行コード▼ のさらにあとで、Empty ですから、これは シートに
>貼り付ける必要はないので、 (0)〜 (2) までの 3行を貼り付ける、というこ
>とになるので、
>> .Resize(UBound(d))
>というのは 結果オーライ ではあるのですが。
>
>なので、文字列型変数にGet# はしなくて、バイト型配列に Get# してから
>あとで Unicode文字列に変換します。こうすれば、お尻に余分なスペースが
>つくことはありませんし、スピードもずっと速いです。
>
>  Dim buf() As Byte
>  Dim Filename As String
>  Dim io As Integer
>  Dim strArry As Variant
>  Dim i As Long
>  
>  io = FreeFile()
>  Open Filename For Binary As io
>   ReDim buf(1 To LOF(io))
>   Get io, , buf
>  Close io
>  strArry = Split(StrConv(buf, vbUnicode), vbCrLf)
>
>  For i = 0 To UBound(strArry) - 1
>    Debug.Print strArry(i)
>  Next

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