ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

EXCEL VBAコミュのcsvファイルを開いてさらに違うcsvファイルに保存

  • mixiチェック
  • このエントリーをはてなブックマークに追加
こんにちは。

VBA初心者、プログラミングはある程度のものです。

このたび、仕事の効率化のためマクロを組んでツールかすることです。

やりたい事:
ボタンを押すとファイルを開く(操作者にファイルを選ばせる)画面が出て、
選んだcsvをInputで開き、そのファイル名を少し変更したファイル名のcsvファイルで保存したいと思っています。

最終的にやりたい事:
?元のcsvのデータにある任意の数値を掛けて(もしくは割って)、
 その結果を
?その際に掛けるある数値を操作者に入力させたり、
 データを使用する開始行を操作者に入力させたりとイロイロかんがえています。

[元ファイル]
ファイル名
保存日時 20011/10/29
データ数 3
データ長 9
Time   位置A   位置B   位置C
0 3 3 3
2 3 3 4
3 3 3 5
4 3 2 10
5 3 2 3
6 3 1 3
7 3 0 3

[現在の方法(上手く動作しません)]
Sub make_file1()

Dim Original As String        ’元のファイル名を格納
Dim newFile As String        ’新しいファイル名を格納
Dim ch1 As Integer          ’元のファイルを開くための番号
Dim ch2 As Integer          ’新しいファイルを開くための番号
Dim i As Long            ’行番号を制御する添え字
Dim x As Long            ’各行の要素を制御する添え字
Dim DL As Long            ’データ数
Dim SL As Long            ’データ開始行
Dim EL As Long            ’データ終了行(基本未使用)

Dim data As String         ’開いたデータを格納
Dim dataIn() As String       ’開いたデータをSPLITした後格納する配列
Dim dataOut() As String       ’処理後のデータを格納する配列

  ’ファイル名を取得
Original = Application.GetOpenFilename("csv ファイル,*.csv,asc ファイル,*.asc")
If (Orignal = "" Or IsNull(Original) = True Or Original = "False") Then
'Exit Sub   ’なぜかExitしてしまうのでコメントアウト
End If

  ’新しいファイル名を決める
newFile = Left(Original, InStr(Original, ".csv") - 1) & "_PHS.csv"

  ’元のファイルをInputとして開く
ch1 = FreeFile
Open Original For Input As #ch1

  ’新しいファイルをOutputとして開く(存在しない場合自動で新しくファイルが出来る)
ch2 = FreeFile
Open newFile For Output As #ch2

i = 0

  ’使いたいファイルまでデータを読み捨てる
SL = 5
For i = 1 To SL
Line Input #ch1, data
Next

’データを読んでは書き込む
Do Until EOF(1)

x = 0
Line Input #ch1, data

dataIn = Split(data, " ")
DL = UBound(dataIn)
ReDim dataOut(DL)
'For x = 0 To (DL - 2)
For x = 0 To (DL - 1)
dataOut(x) = dataIn(x)
Write #ch2, dataOut(x);
Next
'dataOut(DL - 1) = dataIn(DL - 1)
dataOut(DL) = dataIn(DL)
Write #ch2, dataOut(DL - 1)
i = i + 1
Loop

Close #ch1
Close #ch2
End Sub

コメント(31)

Input の使い方が理解できていないのかSplitでデータが分けれなかったり、
dataInの配列数が0になってたりしています。l
まず、
>Original = Application.GetOpenFilename("csv ファイル,*.csv,asc ファイル,*.asc")
>If (Orignal = "" Or IsNull(Original) = True Or Original = "False") Then
>'Exit Sub   ’なぜかExitしてしまうのでコメントアウト
>End If

Exitしてしまうのは、変数名が一致していないからだと・・・
マリオさん>
おっしゃるとおりです。
ホント初歩的ミスですね。
チェックポイントが多すぎて初歩的ミスにも気づかないとは。
申し訳ありません。そして、ありがとうございます。
扱うデータによってうまくいかなかったり、
上手くいったりすることがあります。
例の上手くいかないデータは
行数1行と判断されて、
全くデータを扱えません。
なぜでしょうか???

[上手くいかないデータ]
ThisIs fada
Date 2011/10/29
LSB 300 400 0.3
TimeRate 0.001
Time 300
Time Trq Current Angle
0 0 32768 16384
1 205 32765 16382
2 411 32757 16378
3 617 32744 16372

[上手くいくデータ]
This is my a
I love you
I play baseball very
this si a f
0 523 43342 4321
1 523 43342 4321
2 523 43342 4321
3 523 43342 4321
4 523 43342 4321
5 523 43342 4321
>dataInの配列数が0になってたりしています
は文字列の区切りを識別する文字が「 」だからでは?
csvなのでdataはおそらく、「,」区切りだと思いますが
マリオさん>
僕もだと思って、
変えてみたんですが、駄目でした。
ちなみに、そのデータを違うファイル名のcsvに保存してから
その新しいcsvを問題のマクロで開いてみると上手くできましたが。

とりあえず、問題なさそうなのですが、将来的な問題回避のため、
原因を知っておきたいとも思っています。

ちなみに、csvは最初シートを3つ持っていたので、
1つにし、シート名とファイル名を同じにしました。
しかし、今のところ解決していません。

上手くいくとはどういった状態を指すのでしょうか?
私の環境ではとりあえず、エラーなく処理がされたようですが
> まっすんさん

まず、DataInの宣言を String() から Variant にしてみてください

Splitの出力は可変個ですよね?

# ここで実行時エラーが出てもおかしくない気がしますが…


また、区切り文字を変えても駄目との事ですが、csvファイルの「中身」をエディタか何かで確認してみましたか?

欲張らず、1つずつ駄目なところを潰していきましょう
拡張子csvのExcelブックってこた無いですよね(^_^;)?
マリオさん>
上手くいかないというのは、
データを2行目までしか読み込めず、
結果として出来たファイルがブランクとなってしまいます。
(出力を5行目からとしているため)
>12
それは、変数SLを変えれば良いのでは?


因みに、単純に6行目以降を書き出していくだけであれば、例えば

Sub Macro1()
Dim Original As String '元のファイル名を格納
Dim newFile As String  '新しいファイル名を格納
Dim ch1 As Integer   '元のファイルを開くための番号
Dim ch2 As Integer   '新しいファイルを開くための番号
Dim i As Long      '行番号を制御する添え字
Dim x As Long      '各行の要素を制御する添え字
Dim DL As Long     'データ数
Dim SL As Long     'データ開始行
Dim EL As Long     'データ終了行(基本未使用)

Dim data As String   '開いたデータを格納
Dim dataIn() As String '開いたデータをSPLITした後格納する配列
Dim dataOut() As String '処理後のデータを格納する配列

'ファイル名を取得
Original = Application.GetOpenFilename("csv ファイル,*.csv,asc ファイル,*.asc")
If Original = "" Or IsNull(Original) = True Or Original = "False" Then Exit Sub

'新しいファイル名を決める
newFile = Left(Original, InStr(Original, ".csv") - 1) & "_PHS.csv"

'元のファイルをInputとして開く
ch1 = FreeFile
Open Original For Input As #ch1

'新しいファイルをOutputとして開く(存在しない場合自動で新しくファイルが出来る)
ch2 = FreeFile
Open newFile For Output As #ch2

i = 0

'使いたいファイルまでデータを読み捨てる
SL = 5
For i = 1 To SL
  Line Input #ch1, data
Next

'データを読んでは書き込む
Do Until EOF(1)

  x = 0
  Line Input #ch1, data

  dataIn = Split(data, ",")
  DL = UBound(dataIn)
  ReDim dataOut(DL)
  For x = 0 To DL
    dataOut(x) = dataIn(x)
    If x = DL Then
     Print #ch2, dataOut(x)
    Else
     Write #ch2, dataOut(x);
    End If
  Next x
Loop

Close #ch1
Close #ch2
End Sub
ステップ実行やdebug.print/msgbox辺りを使って、
期待通りにデータを遣り取りしているか確認した方が良いですね。
5行目までの捨てデータも、果たして正しく捨てているのかも含めて。

あと、eof(1)はeof(ch1)ですよね?
Amlaidさん>
>まず、DataInの宣言を String() から Variant にしてみてください
やってみようと思います。

ちなみに
String から Variant でいいですか?
Variantは入ってくるものがStringでもLongでもいいっていいみですよね???

>Splitの出力は可変個ですよね?
はい。

>また、区切り文字を変えても駄目との事ですが、csvファイルの「中身」をエディ>タか何かで確認してみましたか?
>欲張らず、1つずつ駄目なところを潰していきましょう
最初に確認してますが、とくに以上は無かったです。

>拡張子csvのExcelブックってこた無いですよね(^_^;)?
これは、ここのトピを立てる前に解決済みです。
まりおさん>
>それは、変数SLを変えれば良いのでは?
SL以降の数値を使いたいのでSLは帰れないです。
つまり、
デー多数は100以上あって、
最初のヘッダーみたいな部分を捨てて、
SL以降のデータファイルを扱いたいってのがやりたいことです。

Amlaidさん>
>あと、eof(1)はeof(ch1)ですよね?
原因がわかりました。
EOFの引数ってデータの番号だったんですね。
ch1は2になってました。
ch2が1だったので、
当然作られたファイルが即EOFとなるので
LOOPからはずれちゃうんだとおもいます。

ありがとうございます。

細かいバグはありますが、とりあえず、
上手くいけそうです。

細かいバグというのはちょっとした記載ミスなどなので、
おそらく自力で消せるかと思います。
ありがとうございます。
>最初のヘッダーみたいな部分を捨てて
それは必ずあるのでしょうか?
その部分の行数は固定なのでしょうか?

必ずあり、行数が固定であるなら、SLは数値を入れるなりしてあげれば良いでしょうが
もし、必ずある訳ではなかったり、行数が変動するのであれば
SLはユーザーが変更するか、何かその部分だと判断するキーワードがあるなら
それを見つけで自動的にSLを変更させるようにしなければ・・・
マリオさん>
ありがとうございます。

必ずでは有りません。
なので、SLにはデータの種類ごとにイロイロカスタマイズできるように
実行側のインターフェースを作ってあるので、
そこで、入力者が処理できるようになっています。

>19
では、実行側がSLの数値を入力させるようにするとか
しなければならないのでは?

現在は「SL = 5」となっているので
5行目までは読むだけで、6行目以降は書き出す
というようになっているはずですから

種類毎にヘッダーのような部分の行数が(あるなしも含めて)定数で
決まっているなら、それを選択させるなり、入力させるなり
すれば良いと思いますが
変数のスペルミスを防ぐには、変数の宣言を強制にするオプション宣言をすれば「宣言されていない」エラーでわかります。
宣言に大文字と小文字を混ぜ、コーティングは全て小文字で打つと、スペルが一致すると宣言に合わせて大文字に変換し、スペルミスがあると変換されないのでわかります。

あとはステップ実行とデバッグ方法を知ると、より作業効率が良いかと。
うまく行かないCSVファイルってwindowsで作られた物ではないんではないでしょうか?
Line Inputはwindowsの改行コード(CRLF)しか改行と判断できません。
UNIXから出されたファイルだと改行コードがLFですんで全部一行で取って来てしまいます。
うまく行かないファイルを一度、改行コードの種類が解るテキストエディタ(秀丸 等)で
開いて確認してみるといいと思います。

>例の上手くいかないデータは
>行数1行と判断されて、
>全くデータを扱えません
改めて、「うまく行かないファイル」を見てみるとどうもLinuxっぽいですね。
改行コードはLFと思われます。
Line Inputで行単位で読み込みたいなら、LFをCRLFに置換してやる必要があります。
処理するファイルの数がそんなにないんなら処理を動かす前にテキストエディタで改行コードを変換してやるのが一番楽かも知れません。
自動処理させたいんなら、Linax側で改行コードを変換して出力する様にするか、
このVBAの処理の前に改行コードの変換処理を入れるかでしょうね。
バイナリモードでオープンしてLOFまで一文字ずつ読み込んで、LF(VBAの組み込み定数ではvbLf)だったらCRLF(同じくvbCrLf)に置換してやれば良いと思います。
まぁ、とりあえず「うまく行かないファイル」の改行コードを確認してみる事をお勧めします。
多分、この「うまく行かない」ファイルが実データの様な気もしますんで避けては通れないと思います。

連続投稿、長レス スンマセンm(_ _)m
マリ男>
おはようございます。
返事遅れてすいません。

>種類毎にヘッダーのような部分の行数が(あるなしも含めて)定数で
>決まっているなら、それを選択させるなり、入力させるなり
その処理は既に入っています。
この取り扱いは非常に簡単なのと、
自分がぶつかっている課題に焦点を当てるために
あえてこのスレでは固定にしています。

私の
>なので、SLにはデータの種類ごとにイロイロカスタマイズできるように
>実行側のインターフェースを作ってあるので、
>そこで、入力者が処理できるようになっています
というのはすでにその処理を反映して、
解決しているという意味です。
のぐち@チャリマニさん>

その方法いいですね。
宣言部は大文字小文字混ざり、
コーディングは小文字のみにする方法。
今後試してみます。
>24
では、どこが解決していないのでしょうか?
[羽]e-bow さん>
ご指摘ありがとうございます。

ただ、前出のように本件は解決しています。

[課題]ファイルの行数が1行とカウントされてしまう。

[原因]EOF(ch1)とすべきところをEOF(1)としていた。
   ch1は2が割り当てられ、ch2に1が割り当てられてました。

   なので、新しく作ったファイル(空ファイル)の行数が
   0行とされてしまうのです。
   ループに入るまでにch1を呼んでいたので、
   行数1となっていると勘違いしていたのです。

また、元データは確かに実データで、
windowsで作るものでは有りませんが、
互換の試験機のcsvデータです。

また、現在使用している元データはそれらのデータを見立てて
windows-EXCELで作成したファイルです。
マリオさん>
課題はマダマダありますが、
当初ココで聞こうとしていたことは17>のように解決したと思っています。

ここでやりたい事:
に関しては解決

最終的にやりたい事:
に関しては課題が沢山あります。
?マクロを他の人が編集できないようにしたい。

?Line Input 命令で取得するデータの型がどのような法則で文字列として入ってくるか?
※今、二つ目のマクロを組んでいます。
最初のマクロで出来あがったファイルを開き、
あるデータ処理をして更に新しく作成したファイルに保存する方法です。

Line Input #ch1, data
どちらもcsvふぁいるに文字列としてはいっているのに
1つは
data = ""A","B","C","D"
もう一方は
data = "A,B,C,D"

なので、とりあえずの対策は立てれますが、
根本の理解にはならないので考えなくてはならないと思っています。

?exeファイル化
このマクロがついているファイルの入力部を
ユーザーフォームのインターフェースにして、
exeファイルを立ち上げると作業できるようにしたいと思っています。
とりあえず、
>マクロを他の人が編集できないようにしたい

保護をかければ済む話では?
?データを後ろから読めるかどうか
今までは読み込んだファイルを掛け算や足し算など下だけだったので、
読み込んだ順に処理すればよかったのですが、

次は
ある行を処理する際1つ前の行の数値を使って掛け算引き算するなどします。
⇒これも読み込んだ順に処理すればいいので問題ありません。

その次は
1番下の行をそのままにして、その前の行は1番したの行の数値を使って処理します。
さらに、3番目に下の行は2番目の行の結果を使用して処理します。
    4番目に下の行は3番目の行の結果を使用して処理します。
    5番目に下の行は4番目の行の結果を使用して処理します。
    (1番上の行がデータ名として)
    2番目に上の行は3番目に上の行の結果を使用して処理します。
こういった処理をしたいので、
データを逆側から読めればと思っています。
マリオさん>

そのとおりです。

保護掛けて終了です。

ログインすると、残り2件のコメントが見れるよ

mixiユーザー
ログインしてコメントしよう!

EXCEL VBA 更新情報

EXCEL VBAのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。