advanced help
per page, with , order by , clip by
Results of 1 - 1 of about 14729 for VBA�������������� (0.003 sec.)
[[20130808161622]]
#score: 3408
@digest: 756cd36296954611307b72c13b941691
@id: 63154
@mdate: 2013-08-28T12:57:36Z
@size: 54510
@type: text/plain
#keywords: outpos (258872), inpos (203901), outfn (185665), h0d0a (173756), inbuf (136421), infn (108745), 票数 (98388), 投票 (68469), put (54769), fno (44615), java (36341), byte (32402), 定長 (31226), freefile (27694), dat (23836), ナリ (22642), フェ (19660), ェン (19644), 力フ (19362), 入出 (17070), レコ (16892), ィー (10828), 末尾 (10320), バイ (10305), ファ (8719), get (8551), 速度 (7915), イナ (7726), ichinose (7438), ルド (7282), 連番 (7085), 出力 (6937)
『固定長テキスト処理について』(フェンダー)
お世話になります。 [[20130730084752]]で質問した話の続きになります。 COBOL言語で作成されたシステムという事で 下記のような1レコードに対し1件の 固定長テキストデータという事でほぼ決まりのようです。 現在は1バイトEBCDICと 2バイトKEISですが 今後は1byte2byteともにAsciiになるということになります。 今回の下記のテスト例で言いますと レコード長 30byte 1項目目 5byte 2項目目 10byte 3項目目 15byteになるのですが 001 あああ おおおお 002 いい いいいい 003 うううううかかかかかかか 固定長テキストデータを 項目ごとにカンマで区切りCSVデータのように ファイルを生成することを まず考えたいのですが 上記のようなイメージのサンプルデータがあるサイトはありますでしょうか? もしくはアドバイスの方 よろしくお願いいたします。 (フェンダー) ---- 質問するのも良いと思いますが、「固定長 CSV 変換」などのキーワードで検索は してみたでしょうか。 世にあふれた作業だと思いますので、まずは探してみてはと思います。 蛇足ですが、2byte の ASCII 文字というものは存在しません。 (Mook) ---- (Mook)さん もちろん色々探しました。 専用コンバーターだったりなかなか参考になるものがなかったので・・・ もう少し探してみます。 (フェンダー) ---- 例えば http://www.asahi-net.or.jp/‾ef2o-inue/vba_o/sub05_110_055.html などは参考にならなかったのでしょうか。 フリーウェアでも http://download.goo.ne.jp/software/contents/soft/winnt/util/se432913.html のようなものがあるようですが、使用できないでしょうか。 (Mook) ---- (Mook)さん 質問する前にチェックしてたサイトですが サンプルコードもありますし、よく確認してなかったです。 フリーウェアは、仕様によって変わると思いますので 対応出来る場合もあるかと思いますが厳しいかと思われます。 どうもありがとうございました。 (フェンダー) ---- 以前にも記述しましたが、固定長のファイルなら、VBAの標準ファイルI/Oにも 専用モードがあります。 AKBの総選挙結果を例にとると・・・、 3バイト(順位) 8バイト(氏名)8バイト(得票数)の計19バイトが1レコードのファイルを考えます 001指原莉乃 150,570 002大島優子 136,503 003渡辺麻友 101,210 こんなデータです。 新規ブックの標準モジュールに Option Explicit Type rec rnk As String * 3 nm As String * 8 vl As String * 8 End Type Type brec rnk(1 To 3) As Byte nm(1 To 8) As Byte vl(1 To 8) As Byte End Type '========================================= Sub 書き込み() Dim fno As Long Dim dat As rec On Error Resume Next Kill ThisWorkbook.Path & "¥test.dat" On Error GoTo 0 fno = FreeFile Open ThisWorkbook.Path & "¥test.dat" For Random As #fno Len = 19 With dat .rnk = Format(1, "000") .nm = "指原莉乃" .vl = Space(8) RSet .vl = Format(150570, "#,##") End With Put #fno, , dat With dat .rnk = Format(2, "000") .nm = "大島優子" .vl = Space(8) RSet .vl = Format(136503, "#,##") End With Put #fno, , dat With dat .rnk = Format(3, "000") .nm = "渡辺麻友" .vl = Space(8) RSet .vl = Format(101210, "#,##") End With Put #fno, , dat Close #fno End Sub '================================================ Sub 読み込み() Dim fno As Long Dim dat2 As brec Dim g0 As Long fno = FreeFile Open ThisWorkbook.Path & "¥test.dat" For Random As #fno Len = 19 For g0 = 1 To LOF(fno) / 19 Get #fno, , dat2 With dat2 Debug.Print StrConv(.rnk(), vbUnicode) & " : " & StrConv(.nm(), vbUnicode) & " : " & StrConv(.vl(), vbUnicode) End With Next Close #fno End Sub *ブックを一度適当な個所に保存後に 書き込みを実行してください。これでブックと同じフォルダ上に固定長ファイルが作成されます。 次に問題の読み込みは、読み込みを実行してください。 正しくデータが取得できると思います。 ポイントは、 Typeステートメントでユーザー定義型の変数を定義すること 読み込みは Getステートメントを使用する でしょうか!! Cobolからの出力ファイル形式が全部文字列型のデータなら、よいですが、 Cobol言語にも VBAでいう Single型やDouble型などのバイナリエディタなどでも何のデータなのか 分からないような変数はあります。 汎用的に利用できる出力ファイルだとすれば、あまりこういう変数は使いませんが、 逆にこれらの変数を使うと簡単に中の内容は想像できませんから、そういう目的もあるなら、 可能性としては、0ではありませんね!! そのような場合でも上記の手法であれば、Typeステートメントの定義次第で 簡単にデータ取得はできます。 検討してみてください ichinose ---- 続きです。 >固定長テキストデータ これが行区切り記号あり(1レコードの末尾に&h0D0Aがある)固定長データの場合。 前回データを以下のように変更 AKBの総選挙結果を例にとると・・・、 3バイト(順位) 8バイト(氏名)6バイト(得票数)の 計17バイトが1レコード(実際には&h0D0Aを含めて19バイト)のファイルを考えます 001指原莉乃150570 002大島優子136503 003渡辺麻友101210 説明の都合上、数字の区切りカンマを取りました。 こんなデータです。 新規ブックの標準モジュール(Module1)に '============================================================ Option Explicit Type rec rnk As String * 3 nm As String * 8 vl As String * 6 clf As String * 2 End Type Sub 書き込み2() Dim fno As Long Dim dat As rec On Error Resume Next Kill ThisWorkbook.path & "¥test2.txt" On Error GoTo 0 fno = FreeFile Open ThisWorkbook.path & "¥test2.txt" For Random As #fno Len = 19 With dat .rnk = Format(1, "000") .nm = "指原莉乃" .vl = Space(6) RSet .vl = CStr(150570) .clf = vbCrLf End With Put #fno, , dat With dat .rnk = Format(2, "000") .nm = "大島優子" .vl = Space(6) RSet .vl = CStr(136503) End With Put #fno, , dat With dat .rnk = Format(3, "000") .nm = "渡辺麻友" .vl = Space(6) RSet .vl = CStr(101210) End With Put #fno, , dat Close #fno End Sub 別の標準モジュール(Module2)にADO I/O プロシジャー群(テキストファイル用) '============================================================== Option Explicit '====================================================== Private cn As Object '============================================================= Function open_ado_text(path As String) As Long 'adoでテキストにアクセス On Error Resume Next Dim link_opt As String Set cn = CreateObject("adodb.connection") link_opt = "Driver={Microsoft Text Driver (*.txt; *.csv)};" & _ "DBQ=" & path & ";" & "ReadOnly=0" cn.Open link_opt open_ado_text = Err.Number On Error GoTo 0 End Function '============================================================= Sub close_ado() 'クローズ On Error Resume Next cn.Close Set cn = Nothing On Error GoTo 0 End Sub '============================================================= Function exec_sql(sql_str, Optional rs As Variant) As Long 'Sqlの実行 On Error Resume Next If IsMissing(rs) Then cn.Execute sql_str Else Set rs = cn.Execute(sql_str) End If exec_sql = Err.Number If Err.Number <> 0 Then MsgBox Err.Description On Error GoTo 0 End Function '========================================================================== Function mk_schema_ini(path As String, dat() As String) As Long 'schema.iniの作成 On Error GoTo err_mk_schema_ini Dim fno As Long Dim didx As Long mk_schema_ini = 0 fno = FreeFile() Open path & "¥schema.ini" For Output As #fno For didx = LBound(dat()) To UBound(dat()) Print #fno, dat(didx) Next Close #fno ret_mk_schema_ini: On Error GoTo 0 Exit Function err_mk_schema_ini: MsgBox Err.Description mk_schema_ini = Err.Number Resume ret_mk_schema_ini End Function '============================================================= Function del_schema_ini(path As String) 'schema_iniの削除 On Error Resume Next Kill path & "¥schema.ini" On Error GoTo 0 End Function 別の標準モジュール(Module3)に固定長テキストファイル読み込みプロシジャー '======================================================================== Option Explicit '============================================================== Sub 読み込み2() Dim ret As Long Dim dat(1 To 8) As String Dim rs As Object Dim ans As Variant dat(1) = "[test2.txt]" dat(2) = "ColNameHeader = False" dat(3) = "Format = FixedLength" dat(4) = "MaxScanRows = 0" dat(5) = "CharacterSet = OEM" dat(6) = "Col1=rnk char width 3" dat(7) = "Col2=nm Char Width 8" dat(8) = "Col3=vl Char Width 6" Call mk_schema_ini(ThisWorkbook.path, dat()) ret = open_ado_text(ThisWorkbook.path) If ret = 0 Then ret = exec_sql("select * from test2.txt;", rs) If ret = 0 Then Do Until rs.EOF MsgBox "順位 : " & rs!rnk & " 氏名 : " & rs!nm & " 得票数 : " & rs!vl rs.movenext Loop rs.Close Else MsgBox Error(ret) End If close_ado End If Call del_schema_ini(ThisWorkbook.path) Erase dat() Set rs = Nothing End Sub *ブックを一度適当な個所に保存後に 書き込み2 を実行してください。これでブックと同じフォルダ上に固定長テキストファイルが作成されます(行区切りあり)。 次に問題の読み込みは、読み込み2 を実行してください。 正しくデータが取得できると思います。 ポイントは、 Schema.iniというファイルに固定長ファイルtest2.txtの情報を書き込む SQLでデータを取り出す adoのRecordSetの扱い方でしょうか!! >固定長テキストデータを >項目ごとにカンマで区切りCSVデータ 後は、取り出したデータをもとにこれをCSVに変換すればよいです。 実は、CSVファイルは、作成するCSVファイルの情報をSchema.iniファイルに追加し、 SQLをそれように変更すれば、簡単に作ってくれます(Select into を使う)が、 それを調べるか、Textstream等を使ってカンマ区切りに編集するのもよいでしょうね 以上です。 ichinose ---- 色々ありがとうございます。 ユーザー定義型の変数を定義して バイナリ入出力のように getステートメントを使用して、検証し 現在実行結果が思うようにいかない感じでした。 続いて、記述して頂いたコードと アドバイスを参考に 色々調べながら試してみます。 時間はありますので、アドバイス頂けて 助かります。 (フェンダー) ---- >ユーザー定義型の変数を定義して >バイナリ入出力のように >getステートメントを使用して、検証し >現在実行結果が思うようにいかない感じでした。 うまくいかない現象を具体的に説明してください。 私の方で再度、投稿したコードを試してみましたが、正常にデータが取得できています。 >Debug.Print StrConv(.rnk(), vbUnicode) & " : " & StrConv(.nm(), vbUnicode) & " : " & StrConv(.vl(), vbUnicode) これが問題で結果が表示されない ということなら、 msgbox StrConv(.rnk(), vbUnicode) & " : " & StrConv(.nm(), vbUnicode) & " : " & StrConv(.vl(), vbUnicode) これに変更してください。そうでなかったら、具体的な説明をお願いします。 ichinose ---- EBCDICとKEISですか? 前のご質問ではEBCDIKとKEISでしたし、普通はEBCDIKとKEISの 組合せで使用し、EBCDICとKEISにはしないはずですが。 正確な情報を出さないと、 欲しい回答は得られませんよ。 EBCDICとEBCDIKの違いをご存知ないようならば、日立のページにある情報を 確認することです。固定長ファイルのアクセスならばMookさんが教えてくれている ページが参考になりますし、そこまでしなくとも30byte全てByte型配列1つで 読むだけでも十分でしょう。(改行コードが無いようですが、本当に?) http://www.hitachi.co.jp/Prod/comp/soft1/manual/pc/d3J3820/ISUS0268.HTM http://www.hitachi.co.jp/Prod/comp/soft1/manual/ws/c3D5820/CLNT0235.HTM 面倒なのはコード変換部分です。といっても、前回のご質問では変換は他者が 行なっているとの事なので、何も悩む部分は無いように思えます。 (???) ---- もう少し詳しく指摘すると、5byteのデータはKI/KOを含む余地が殆ど無いので、ここはEBCDIKと思われます。 10byteは、全てKEISコードでしょうか。要確認。 全て漢字の場合、データ長は偶数のはずなので、15byteは全角半角混在と思います。 データ中にKI/KOコードは含みますか? KI前提でEBCDIKとKEISの混在かと思いますが、要確認。 なお、データ中に&H0Aが含まれる場合、KEISではKI/KOの先頭1byteであり、改行ではない事に注意。 (???) ---- 失礼いたしました。 EBCDIKとKEISになります。 >(改行コードが無いようですが、本当に?) データは区切りのないファイルとなります。 >面倒なのはコード変換部分です。といっても、前回のご質問では変換は他者が 行なっているとの事なので、何も悩む部分は無いように思えます。 申し訳ございません。 こちらがよく分からないのですが もう一度整理させて頂きます。 現在EBCDIKとKEISのデータに関しては 対応出来ております。 特に悩んでないのですが・・・ (フェンダー) ---- 前スレも見て確認です。 現在行っている処理が、システム変更により、 input: >現在は1バイトEBCDICと > 2バイトKEISですが >今後は1byte2byteともにAsciiになる output: 記載はないので仕様がわかりませんが、変更なし ということですね。 (cai) ---- >うまくいかない現象を具体的に説明してください。 ichinoseさんのコードは参考でチェックさせて頂きましたが アドバイスを元に バイナリの入出力にそのまま変数を変数を定義している状態ですが Textstreamを使用して区切りをつける方法等 調べている感じです。 下記のコードがVBAになります。 ファイルの中身 001指原莉乃150570 002大島優子136503 003渡辺麻友101210 現在 model1 Sub Main() Dim InFileName As String Dim OutFileName As String Dim InFN As Long '入力ファイルハンドル番号 Dim OutFN As Long '出力ファイルハンドル番号 Dim InFileLen As Long '入力ファイルのサイズ Dim InPOS As Long '入力ファイル位置 Dim OutPOS As Long '出力ファイル位置 InFileName = "¥SAMPLE.dat" OutFileName = "¥outSAMPLE.dat" InFN = FreeFile Open InFileName For Binary As #InFN OutFN = FreeFile Open OutFileName For Binary As #OutFN InPOS = 1 OutPOS = 1 InFileLen = LOF(InFN) Do While (InPOS < InFileLen) '1************************ Get #InFN, InPOS, フィールド1 Put #OutFN, OutPOS, フィールド1 InPOS = InPOS + 3 OutPOS = OutPOS + 3 '1************************ '2************************ Get #InFN, InPOS, フィールド2 Put #OutFN, OutPOS, フィールド2 InPOS = InPOS + 8 OutPOS = OutPOS + 8 '************************ '3************************ Get #InFN, InPOS, フィールド3 Put #OutFN, OutPOS, フィールド3 InPOS = InPOS + 6 OutPOS = OutPOS + 6 '************************ ipos = ipos + 1 Loop Close #InFN Close #OutFN End Sub model2 Public フィールド1(1 To 3) As Byte '1 Public フィールド2(1 To 8) As Byte '2 Public フィールド3(1 To 6) As Byte '3 上記コードでおかしな箇所をご指摘ください。 それとこちらは 言語が違くて申し訳ございませんが ichinoseさんのアドバイスから作成してますので 記載します。 カンマを含んだテキストデータを 入出力する際 byte[] から String をにし 区切りはバーティカルバーに設定。 すると 下記のソースでの 結果が現在こんな結果になります。 出力前 001指原莉乃15,570 002大島優子13,503 003渡辺麻友10,210 出力後 001|指原莉乃|15,570 002|大島優子|13,503 003|渡辺麻友|10,210 String arrayline = recordlength; try { byte[] bytes = arrayline.getBytes("MS932"); byte[] first = new byte[3]; //連番 byte[] second = new byte[8]; //氏名 byte[] third = new byte[6]; //金額 int findex = 0; int sindex = 0; int tindex = 0; for (int i = 0; i< bytes.length;i++){ if(i< 3){ first[findex] = bytes[i]; findex ++ ; } else if(i< 11){ second[sindex] = bytes[i]; sindex ++ ; } else if(i< 17){ third[tindex] = bytes[i]; tindex ++ ; } } System.out.print(new String(first,"MS932")+ "|"); System.out.print(new String(second,"MS932")+ "|"); System.out.println(new String(third,"MS932")); } catch (UnsupportedEncodingException e) { e.printStackTrace();} } この方法で問題ないのか?他の仕様の際対応出来るのか こちらが懸念されるとこだと思います。 (フェンダー) ---- つまりは、既にコード変換は終わっている。しかしカンマも改行もないので、 要所にコード挿入してcsv形式として開けるようにしたい、ということ? (ならばEBCDIKだのKEISだの、余計なコード情報は書かないで欲しい) 標準モジュールで以下を実行。 Type aaa b1(4) As Byte b2(9) As Byte b3(14) As Byte End Type Sub test() Dim F1 As Integer Dim F2 As Integer Dim Rec As aaa F1 = FreeFile Open "¥SAMPLE.dat" For Binary As #F1 F2 = FreeFile Open "¥SAMPLE.csv" For Binary As #F2 While EOF(F1) = False Get #F1, , Rec Put #F2, , Rec.b1 Put #F2, , "," Put #F2, , Rec.b2 Put #F2, , "," Put #F2, , Rec.b3 Put #F2, , vbCrLf Wend Close #F2 Close #F1 End Sub .NETのコードが書けるなら、何も遅いExcelVBAなぞ使わなくても良さそうな…。 (???) ---- 因みに、文字コード1byte 2byteともにshift-jisとお伝えしていましたが 仕様によってはバイナリデータも混在しているとの事です。 どのようなバイナリデータが含まれるのかは 実際テストデータを授受してからの話に なると思いますが… 現在コード変換が出来ている入出力のソースは 保留になりそうなので バイナリを操作するとなると VBAの方がいいかなと。 (フェンダー) ---- Javaは、知らないのでなんとも言えませんが、 CSVファイル用に取得したランダムファイルから取得したデータの間に「,」を入れて、後は繋げれば 良いのですから、方法はいくらでもあると思います。 色々考えてみてください。 私は、ここは、フェンダーさんがご自分で考える範囲だと 最初から決めていましたので・・・。できると思いますよ!! それより・・・、 >仕様によってはバイナリデータも混在しているとの事です。 あくまでも想像ですが、これの扱いが今までとは違うかもしれません。 バイナリデータの値と内部表現をいくつも事例から調べるなりしてみてください そのためには、ファイルの内部表現が簡単に見ることができるバイナリーエディタが必要です。 フリーでDLできるもので構いませんから、ないのなら準備はしておいてください。 ichinose ---- ご連絡ありがとうございます。 JAVAは基本的に 件数が多いデータを早く処理したい為に 使っているのですが VBAもJAVAも同じですので こちらで教えて頂いた内容を JAVAで書いたりもしてます。 (JAVAの方が便利なメソッドが用意されていて 内容によっては初心者には便利) まだ時間はありますので、色々試してみますが 出来てるものをそのまま使用するとなると エラー時に対応出来なくなるもしくは 想像外の事がおきたりすることもあると思います。 本来作成したいものは 分かりやすいコードで、色々な仕様と 色々なエラーにすぐに対応したいので 出来れば、対応出来てるプログラムと併用できる ものが、効率が良く安心かなと思ってます。 バイナリ型に関しては色々と調べて事前準備をしますが こちらはテストデータを授受してからになりそうです。 バイナリエディタに関してはStirlingを使用してます。 byte数(レコード長)は必ず把握しなければ しっかりしたデータが生成できないので バイナリ型やパック型等、数値変換する際には 必ずバイト数をチェックしてます。 (フェンダー) ---- (???)さん。 色々コメントありがとうございます。 こちらのコードも参考にさせて頂きます。 (フェンダー) ---- 下記のコードで解決致しました。 まずデータは 001指原莉乃150570 002大島優子136503 003渡辺麻友101210 変数は1レコードの末尾に&h0D0Aがある場合を 考慮しh0D0A(1 To 2) As Byteを追加し 各フィールドごとのカンマを付加させる分 読み込むbyte数に対して 領域を1byteずつ確保しました。 '1フィールド******************* Get #InFN, InPOS, 連番 Put #OutFN, OutPOS, 連番 InPOS = InPOS + 3 Put #OutFN, , "," OutPOS = OutPOS + 4 '************************ '2フィールド****************** Get #InFN, InPOS, 氏名 Put #OutFN, OutPOS, 氏名 InPOS = InPOS + 8 OutPOS = OutPOS + 9 Put #OutFN, , "," '************************ '3フィールド****************** Get #InFN, InPOS, 投票数 Put #OutFN, OutPOS, 投票数 InPOS = InPOS + 6 OutPOS = OutPOS + 6 '************************ '1レコードの末尾&h0D0A************* Get #InFN, InPOS, h0D0A Put #OutFN, OutPOS, h0D0A InPOS = InPOS + 2 OutPOS = OutPOS + 2 '************************ Public 連番(1 To 3) As Byte Public 氏名(1 To 8) As Byte Public 投票数(1 To 6) As Byte Public h0D0A(1 To 2) As Byte '1レコードの末尾に&h0D0Aがある場合 これにより結果が 001,指原莉乃,150570 002,大島優子,136503 003,渡辺麻友,101210 となりました。 JAVAではgetBytesという方法で操作しましたので 1レコードの末尾を気にすることなく??? 出来ると思うのですが 現在あるVBAの方が 仕様により頭に4byteある可変長データの場合とか ありますし、また javaで考えるより VBAの方が検証せずに安心かなと・・・ バイナリのデータに関して 対応できない場合ご相談させてください。 どうもありがとうございました。 (フェンダー) ---- できたら、実行すれば、手直しせずに作動するプログラムの提示が見たかったのですが・・・。 まっ、でもおおよそはわかりました。 因みにサンプル作成用のコードを 標準モジュールに '====================================================================== Option Explicit Type rec rnk As String * 3 nm As String * 8 vl As String * 6 End Type Sub mk_sample() Dim fno As Long Dim dat As rec Dim g0 As Long Const rcnt = 100000 'ここの数を変えると、容量の違うファイルが作成できます '↑この状態だと30万件の固定長レコードが作成されます On Error Resume Next Kill ThisWorkbook.Path & "¥sample.dat" On Error GoTo 0 fno = FreeFile Open ThisWorkbook.Path & "¥sample.dat" For Random As #fno Len = Len(dat) For g0 = 1 To rcnt With dat .rnk = Format(1, "000") .nm = "指原莉乃" .vl = CStr(150570) End With Put #fno, , dat With dat .rnk = Format(2, "000") .nm = "大島優子" .vl = CStr(136503) End With Put #fno, , dat With dat .rnk = Format(3, "000") .nm = "渡辺麻友" .vl = CStr(101210) End With Put #fno, , dat Next Close #fno End Sub 尚、一度適当な場所に保存後に実行してください。 コードを拝見して 気になったことです。 1 Public変数の使用 Public 連番(1 To 3) As Byte Public 氏名(1 To 8) As Byte Public 投票数(1 To 6) As Byte Public h0D0A(1 To 2) As Byte Public変数を コードとは別のモジュールに宣言していますが、これは止めた方がよいです。 CSV変換のプログラム内で 連番という配列は、ファイルから読み込むための変数ですよね? これを他のモジュールに宣言してコードがあるモジュールと変数を宣言したモジュールの関わりを 強くする意味がありません。 この変数は、CSV変換するプロシジャーの中で使うだけですから、プロシジャー内に宣言すれば よいですね!! よって、 標準モジュールに '================================================================= Option Explicit Sub Main() Dim 連番(1 To 3) As Byte Dim 氏名(1 To 8) As Byte Dim 投票数(1 To 6) As Byte Dim h0D0A(1 To 2) As Byte '1レコードの末尾に&h0D0Aがある場合 Dim InFileName As String Dim OutFileName As String Dim InFileName As String Dim InFN As Long '入力ファイルハンドル番号 Dim OutFN As Long '出力ファイルハンドル番号 Dim InFileLen As Long '入力ファイルのサイズ Dim InPOS As Long '入力ファイル位置 Dim OutPOS As Long '出力ファイル位置 h0D0A(1) = &HD h0D0A(2) = &HA On Error Resume Next Kill OutFileName On Error GoTo 0 InFileName = ThisWorkbook.Path & "¥SAMPLE.dat" OutFileName = ThisWorkbook.Path & "¥SAMPLE.csv" InFN = FreeFile Open InFileName For Binary As #InFN OutFN = FreeFile Open OutFileName For Binary As #OutFN InPOS = 1 OutPOS = 1 InFileLen = LOF(InFN) Do While (InPOS < InFileLen) Get #InFN, InPOS, 連番 Put #OutFN, OutPOS, 連番 InPOS = InPOS + 3 Put #OutFN, , "," OutPOS = OutPOS + 4 '************************ '2フィールド****************** Get #InFN, InPOS, 氏名 Put #OutFN, OutPOS, 氏名 InPOS = InPOS + 8 OutPOS = OutPOS + 9 Put #OutFN, , "," '************************ '3フィールド****************** Get #InFN, InPOS, 投票数 Put #OutFN, OutPOS, 投票数 InPOS = InPOS + 6 OutPOS = OutPOS + 6 '************************ '1レコードの末尾&h0D0A************* Get #InFN, InPOS, h0D0A Put #OutFN, OutPOS, h0D0A InPOS = InPOS + 2 OutPOS = OutPOS + 2 Loop Close #InFN Close #OutFN Erase 連番() Erase 氏名() Erase 投票数() Erase h0D0A() End Sub 2 Get及び、Putの書式 GetやPutステートメントの書式が読み込み位置や書き込み位置を 指定した書式や指定しない書式が混在しています。 >Put #OutFN, OutPOS, 氏名 >Put #OutFN, , "," GetやPutステートメントは、読み込み又は、書き込み位置を指定しなければ、 順次 読み込み 書き込みをしてくれます。 又、指定しない方が若干でも処理は速いですよ!! 先のコードは、 '======================================================================= Sub Main2() Dim 連番(1 To 3) As Byte Dim 氏名(1 To 8) As Byte Dim 投票数(1 To 6) As Byte Dim h0D0A(1 To 2) As Byte '1レコードの末尾に&h0D0Aがある場合 Dim InFileName As String Dim OutFileName As String Dim InFileName As String Dim InFN As Long '入力ファイルハンドル番号 Dim OutFN As Long '出力ファイルハンドル番号 Dim InFileLen As Long '入力ファイルのサイズ Dim g0 As Long h0D0A(1) = &HD h0D0A(2) = &HA InFileName = ThisWorkbook.Path & "¥SAMPLE.dat" OutFileName = ThisWorkbook.Path & "¥SAMPLE.csv" On Error Resume Next Kill OutFileName On Error GoTo 0 InFN = FreeFile Open InFileName For Binary As #InFN OutFN = FreeFile Open OutFileName For Binary As #OutFN InFileLen = LOF(InFN) For g0 = 1 To LOF(InFN) / 17 Get #InFN, , 連番 Put #OutFN, , 連番 Put #OutFN, , "," '2フィールド****************** Get #InFN, , 氏名 Put #OutFN, , 氏名 Put #OutFN, , "," '************************ '3フィールド****************** Get #InFN, , 投票数 Put #OutFN, , 投票数 '************************ '1レコードの末尾&h0D0A************* Get #InFN, , h0D0A Put #OutFN, , h0D0A Next Close #InFN Close #OutFN Erase 連番() Erase 氏名() Erase 投票数() Erase h0D0A() End Sub と書き換えることができます。 3 Get Putの使用頻度 最近は、ファイルの読み書きも結構速くなってきていますが、 一般的には、プログラム全体から見て、ファイルの読み書きは、速度が比較的遅くなる 箇所です。よって、処理速度向上のため、なるべく、Get及び、Putの使用頻度を減らすことを考えます。 例えば、一回にGetでファイルのすべてのデータを読み込み、csvファイル用に データを編集し、一回のPut(または、Print等)ですべてデータを書き込む このようにプログラムを作成すれば、Get、PutというファイルI/Oは、一回ずつで 済むので処理速度は、一般的には、速くなります。 が、ファイルの容量が莫大な場合は、一度に全部のデータを読み込む方法だと メモリ不足を起こす可能性がありますから、ファイル容量と相談する必要があります。 OSのレコードとバッファの関係をコード内でシミュレートして効率よく ファイルデータを読み書きする方法もありますが、 1レコード読み込み、編集、1レコード書き込みに変えるだけでも 処理速度の向上は、ありますよ!! '============================================================================= Option Explicit Type indat b1(1 To 3) As Byte b2(1 To 8) As Byte b3(1 To 6) As Byte End Type Sub test3() Dim f1 As Integer Dim f2 As Integer Dim rec As indat Dim g0 As Long Dim odat(1 To 3) As String On Error Resume Next f1 = FreeFile Open ThisWorkbook.Path & "¥SAMPLE.dat" For Random As #f1 Len = LenB(rec) f2 = FreeFile Open ThisWorkbook.Path & "¥SAMPLE.csv" For Output As #f2 For g0 = 1 To LOF(f1) / Len(rec) Get #f1, , rec odat(1) = StrConv(rec.b1, vbUnicode) odat(2) = StrConv(rec.b2, vbUnicode) odat(3) = StrConv(rec.b3, vbUnicode) Print #f2, Join(odat(), ",") Next Close #f2 Close #f1 End Sub 先の mk_sampleの const rcnt=1000000 百万ぐらいでファイルを作成して、 処理速度を比べてみてください。 追伸 EOF関数を使ったコードを拝見しましたが、 このEOF関数、ファイルをオープンするモードによって、Trueを返すタイミングが違いますから、 注意してください。 例 Sub Eof_test() Dim fno As Long Dim dat As Byte fno = FreeFile Open ThisWorkbook.Path & "¥sample2.dat" For Output As #fno Close #fno MsgBox "空のファイル 「Sample2.Dat」を作成しました" & vbCrLf & _ "これを Inputモードでオープンすると・・・・" fno = FreeFile Open ThisWorkbook.Path & "¥sample2.dat" For Input As #fno MsgBox "オープン直後にEOF(fno)の値は " & EOF(fno) Close #fno MsgBox "次にBinaryモードでオープンすると・・・・" fno = FreeFile Open ThisWorkbook.Path & "¥sample2.dat" For Binary As #fno MsgBox "オープン直後にEOF(fno)の値は " & EOF(fno) Get #fno, , dat MsgBox "一度Getステートメント実行後のEOF(fno)の値は " & EOF(fno) Close #fno End Sub このコードも一度保存後に実行してください。 私の感覚からすると、Binaryモード時のEOFの値の推移の方が慣れしたんだ 手順ですが・・・・。 以上、気になったことを投稿しました。 ichinose ---- >Public変数を コードとは別のモジュールに宣言していますが、これは止めた方がよいです。 >CSV変換のプログラム内で 連番という配列は、ファイルから読み込むための変数ですよね? わざわざサンプルデータも添えて頂き アドバイスどうもありがとうございます。 こちらはサンプルになりますので、 カンマ以外の書き込みは想定しておりません。 仕様により、1レコードの配列(フィールド)が 1000近く存在する場合もありますので(通常が100〜150) そうなると別のモジュールに宣言し2つのモジュールで 分けた方が管理しやすいと いった理由でしたので了解致しました。 JAVAは基本的に 件数が多いデータを早く処理したい為に 使っているのですがと発言してしまったのですが 現状の件数ですとすいませんがこちらはそれほど重要ではありません。 現在のプログラムで100万件ほどの処理を検証済みですが 1レコードの長さによりますが(1〜5分で済みます) 固定長データよりCSVのプログラムの方が若干遅いかな?ぐらいで済んでます。 それよりかはKEIS固定長データからCSVに生成する システムの方が100万件ですと 30分近くかかりますのでそれから比べたらぜんぜん速いです。 私がVBAに応用が利かないこともありますので どうせ初めから勉強するなら、オブジェクト指向の言語を 覚えようというぐらいの理由になります。 じゃーなぜVBAも使うの?と言われそうですが 効率の問題で、今ある土台のプログラムは効率の為 使用した方が良いという理由があります。 それと徐々にですが、時間がある時に勉強の為調べながら (コピーバンドのように) VBAのプログラムをJAVAに置き換えてますという感じです。 一応JAVAでは、Bufferクラスを使用して1行ずつ読み書き対応出来るようにして 処理は早くなってますが 今の仕事のボリューム内容でしたら 現在のVBAプログラムで対応出来ます。 〉EOF関数を使ったコードを拝見しましたが、 私は今回の仕様でEOF関数は使用したことはありませんが こちらに関しては知見はありませんでした。 例にならい、今後注意いたします。 (フェンダー) ---- 処理速度の件でアドバイス頂きましたので ご報告だけさせていただきます。 VBAver Sub Main() Dim InFileName As String Dim OutFileName As String Dim InFN As Long '入力ファイルハンドル番号 Dim OutFN As Long '出力ファイルハンドル番号 Dim InFileLen As Long '入力ファイルのサイズ Dim InPOS As Long '入力ファイル位置 Dim OutPOS As Long '出力ファイル位置 InFileName = "¥sample2.dat" OutFileName = "¥sampleout2.dat" InFN = FreeFile Open InFileName For Binary As #InFN OutFN = FreeFile Open OutFileName For Binary As #OutFN InPOS = 1 OutPOS = 1 InFileLen = LOF(InFN) iTitle = 6 'チェック用 エクセルシートのタイトルの行位置 ipos = 7 'チェック用 エクセルシートのデータの行位置・開始 Do While (InPOS < InFileLen) '1フィールド******************* Get #InFN, InPOS, 連番 Put #OutFN, OutPOS, 連番 InPOS = InPOS + 3 OutPOS = OutPOS + 4 Put #OutFN, , "," '************************ '2フィールド****************** Get #InFN, InPOS, 氏名 Put #OutFN, OutPOS, 氏名 InPOS = InPOS + 8 OutPOS = OutPOS + 9 Put #OutFN, , "," '************************ '3フィールド****************** Get #InFN, InPOS, 投票数 Put #OutFN, OutPOS, 投票数 InPOS = InPOS + 6 OutPOS = OutPOS + 6 '************************ '1レコードの末尾&h0D0A************* Get #InFN, InPOS, h0D0A Put #OutFN, OutPOS, h0D0A InPOS = InPOS + 2 OutPOS = OutPOS + 2 '************************ ipos = ipos + 1 Loop Close #InFN Close #OutFN End Sub Public 連番(1 To 3) As Byte Public 氏名(1 To 8) As Byte Public 金額(1 To 6) As Byte Public h0D0A(1 To 2) As Byte '1レコードの末尾に&h0D0A を下記でjavaに書き換えました。 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.io.ByteArrayOutputStream; /** * ファイルの書き込みサンプル *バイナリーデータの読み書き */ public class dat_from_CSV { public static void main(String[] args) { // 読み込むファイルの名前 String inputFileName = "¥¥SAMPLE.dat"; // 書き込むファイルの名前 String outputFileName = "¥¥SAMPLEout.csv"; // ファイルオブジェクトの生成 File inputFile = new File(inputFileName); File outputFile = new File(outputFileName); try { // 入力ストリームの生成 FileInputStream fis = new FileInputStream(inputFile); BufferedInputStream bis = new BufferedInputStream(fis); // 出力ストリームの生成 FileOutputStream fos = new FileOutputStream(outputFile); BufferedOutputStream bos = new BufferedOutputStream(fos); //読み込み用バイト配列◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎ byte[] inbuf = new byte[19]; //読み込み用バイト配列◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎ String b = new String(inbuf);//byte配列から文字列への変換 String tmpstr; byte[] kanma = ",".getBytes("Shift_JIS"); //カンマ書き込み // ファイルへの読み書き int len = 0; //読み込み用バイト配列◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎ while ((len = bis.read(inbuf, 0, 19)) == 19) { //読み込み用バイト配列◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎ //********************************************************************* //1フィールド 連番 byte[] outbuf1=new byte[3] ; outbuf1[0] = inbuf[0] ; outbuf1[1] = inbuf[1] ; outbuf1[2] = inbuf[2] ; bos.write((outbuf1)); //bos.write(inbuf, 0, 3); //inbufから直接書き込む場合 bos.write(kanma); //********************************************************************* //2フィールド 氏名 byte[] outbuf2=new byte[8] ; outbuf2[0] = inbuf[3] ; outbuf2[1] = inbuf[4] ; outbuf2[2] = inbuf[5] ; outbuf2[3] = inbuf[6] ; outbuf2[4] = inbuf[7] ; outbuf2[5] = inbuf[8] ; outbuf2[6] = inbuf[9] ; outbuf2[7] = inbuf[10] ; bos.write((outbuf2)); //bos.write(inbuf, 3, 8); //inbufから直接書き込む場合 bos.write(kanma); //bos.write(unpack(new byte[]{0x01, 0x2F})); //outbuf2)); //********************************************************************* //3フィールド 投票数 byte[] outbuf3=new byte[6] ; outbuf3[0] = inbuf[11] ; outbuf3[1] = inbuf[12] ; outbuf3[2] = inbuf[13] ; outbuf3[3] = inbuf[14] ; outbuf3[4] = inbuf[15] ; outbuf3[5] = inbuf[16] ; bos.write((outbuf3)); //bos.write(inbuf, 11, 6); //inbufから直接書き込む場合 //bos.write(ODRWeight1(outbuf3)); //********************************************************************* //1レコードの末尾&h0D0A byte[] outbuf4=new byte[2] ; outbuf4[0] = inbuf[17] ; outbuf4[1] = inbuf[18] ; bos.write(outbuf4);} //********************************************************************* //********************************************************************* // 後始末 bos.flush(); bos.close(); bis.close(); // エラーがあった場合は、スタックトレースを出力 } catch(Exception e) { e.printStackTrace(); } } 因みに念のため下記が改行なしver &ソース短縮 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.io.ByteArrayOutputStream; /** * ファイルの書き込みサンプル *バイナリーデータの読み書き */ public class dat_from_CSV改行なしver { public static void main(String[] args) { // 読み込むファイルの名前 String inputFileName = "¥¥SAMPLE.dat"; // 書き込むファイルの名前 String outputFileName = "¥¥SAMPLEout.csv"; // ファイルオブジェクトの生成 File inputFile = new File(inputFileName); File outputFile = new File(outputFileName); try { // 入力ストリームの生成 FileInputStream fis = new FileInputStream(inputFile); BufferedInputStream bis = new BufferedInputStream(fis); // 出力ストリームの生成 FileOutputStream fos = new FileOutputStream(outputFile); BufferedOutputStream bos = new BufferedOutputStream(fos); //読み込み用バイト配列◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎ byte[] inbuf = new byte[17]; //読み込み用バイト配列◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎ String b = new String(inbuf);//byte配列から文字列への変換 String tmpstr; byte[] kanma = ",".getBytes("Shift_JIS"); //カンマ書き込み byte[] 改行 ="¥r¥n".getBytes("Shift_JIS"); //カンマ書き込み // ファイルへの読み書き int len = 0; //読み込み用バイト配列◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎ while ((len = bis.read(inbuf, 0, 17)) == 17) { //読み込み用バイト配列◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎◎ //********************************************************************* //1フィールド 連番 bos.write(inbuf, 0, 3); //inbufから直接書き込む場合 bos.write(kanma); //********************************************************************* //2フィールド 氏名 bos.write(inbuf, 3, 8); //inbufから直接書き込む場合 bos.write(kanma); //bos.write(unpack(new byte[]{0x01, 0x2F})); //outbuf2)); //********************************************************************* //3フィールド 投票数 //bos.write(inbuf, 11, 6); //inbufから直接書き込む場合 bos.write(改行);} //********************************************************************* //********************************************************************* // 後始末 bos.flush(); bos.close(); bis.close(); // エラーがあった場合は、スタックトレースを出力 } catch(Exception e) { e.printStackTrace(); } } 1レコードの末尾&h0D0Aの事は知りませんでしたので (その後バイナリエディタでチェックして分かりましたが・・・) 大変勉強になりました。 (フェンダー) ---- データが100万行くらいあるとのことでしたので、高速化のアドバイス。 VBAでもJAVAでも同じですが、I/O回数を減らすことで、大きく性能向上を狙えます。 1行のサイズは小さいようなので、1000行まとめて読み、同じようにまとめて 書くことを考えてみると良いでしょう。 (1行分のbyte配列を、2次元配列にして、1000行分にすれば良い) 大元データをCSV化するのに30分くらいとの事でしたが、こちらも作成者に、 「1000行分まとめてI/Oすれば?」と伝えると、1分くらいで終わるように思います。 (???) ---- >大元データをCSV化するのに30分くらいとの事でしたが、こちらも作成者に、 >「1000行分まとめてI/Oすれば?」と伝えると、1分くらいで終わるように思います。 アドバイスどうもありがとうございます。 プログラムに関しては検討しまして システム会社に相談してみます。 (フェンダー) ---- ちょっと訂正、というかバグです。 前回投稿のプロシジャー Main と Main2 Main >'1レコードの末尾&h0D0A************* >Get #InFN, InPOS, h0D0A >Put #OutFN, OutPOS, h0D0A >InPOS = InPOS + 2 >OutPOS = OutPOS + 2 は、 '1レコードの末尾&h0D0A************* Put #OutFN, OutPOS, h0D0A OutPOS = OutPOS + 2 訂正してください。 読み込み側には、 改行コードはないので・・・・。 Main2 >'1レコードの末尾&h0D0A************* > Get #InFN, , h0D0A > Put #OutFN, , h0D0A は、 '1レコードの末尾&h0D0A************* Put #OutFN, , h0D0A と訂正してください。 尚、プロシジャーmk_sample内の cnt=1000000 '(実質3百万レコード) とcntという定数の値を上記で設定し、作成した Sample.datで実験した場合の処理速度ですが、 私の環境で Main ------ 53秒 Main2 ------ 44秒 test3 ------ 15秒 でした。 ichinose ---- コメントどうもありがとうございます。 ichinoseさんの環境と比較して Main ------ 53秒 Main2 ------ 44秒 test3 ------ 15秒 私の環境で検証させて頂きましたところ Main ------ 1分40秒 Main2 ------ 1分40秒 test3 ------ 29秒 処理速度は遅いですがtest3 のコードですと かなり速度が向上することが 確認できました。 因みに ichinoseさんのコードから作成したSample.datを JAVAで入出力しますと 1秒でした。 バイナリデータや可変長データの処理を考えると VBAの処理で対応する可能性が高いですが・・・ ※実際テストデータを授受した際 新規でJAVAでソースが書けるか分かりませんので・・・ ichinoseさんのSAMPLE.datサイズは48.6MB 最近の仕事で1レコードの長さから作成した 約100万件のSAMPLE.datですとサイズが820MBになります。 参考までに・・・ (フェンダー) ¥test.dat ---- 以下のVBAコードで前回と同じ容量のsample.datを入力データとして、実行した時の 処理時間は、私の環境で 2.4秒というところでした。 '=============================================================== Sub test4() Dim f1 As Long Dim g0 As Long Dim g1 As Long Dim g2 As Long Dim ind() As Byte Dim oud() As Byte Dim tm As Double tm = [now()] On Error Resume Next tm = [now()] Kill ThisWorkbook.Path & "¥sample.csv" On Error GoTo 0 f1 = FreeFile Open ThisWorkbook.Path & "¥sample.dat" For Binary As #f1 ReDim ind(LOF(f1) - 1) Get #f1, , ind() Close #f1 ReDim oud((UBound(ind) + 1) / 17 * 21 - 1) g0 = 0: g1 = 0 Do While g0 <= UBound(ind) For g2 = g0 To g0 + 2 oud(g1) = ind(g2) g1 = g1 + 1 Next oud(g1) = Asc(",") g0 = g2 g1 = g1 + 1 For g2 = g0 To g0 + 7 oud(g1) = ind(g2) g1 = g1 + 1 Next oud(g1) = Asc(",") g0 = g2 g1 = g1 + 1 For g2 = g0 To g0 + 5 oud(g1) = ind(g2) g1 = g1 + 1 Next oud(g1) = &HD oud(g1 + 1) = &HA g0 = g2 g1 = g1 + 2 Loop f1 = FreeFile Open ThisWorkbook.Path & "¥sample.csv" For Binary As #f1 Put #f1, , oud() Close #f1 MsgBox Application.Text([now()] - tm, "hh:mm:ss.00") End Sub これ以上、容量の大きいファイルは、一度の読み込みでは心配ですから、 BufferedOutputStreamやBufferedInputStreamのようなことをVBAで自作する必要が ありそうです。 ichinose ---- コード提示どうもありがとうございます。 自宅の環境ですと2.11秒でした。 かなり速いですね。 VBAですとLine Inputステートメントというもので 読み込みだけは1行ずつ対応出来そうですけどね。 下記の処理はネット環境があるPCで 確認したのですが 実際は個人情報ですのでネット環境がないPCで 作業しますので試せていたいのですが・・・ 環境にもよりますよね。 Main ------ 1分40秒 Main2 ------ 1分40秒 test3 ------ 29秒 因みに今回テストしている固定長→CSVより CSV入出力の方が内容が濃いのですが Bufferedクラスで310MBのファイルを試したとこ 30秒ぐらいで VBAですと2分ぐらいというところでしょうか。 MsgBoxで時間を表示させたわけじゃないので だいたいの時間ですが・・・ 速度よりは安全に処理できるかという方が大事だと 思いますけど。 (フェンダー) ---- >VBAですとLine Inputステートメントというもので >読み込みだけは1行ずつ対応出来そうですけどね このスレッドの最初の方のフェンダーさんの発言に >データは区切りのないファイルとなります。 という記述がありました。 このようなファイルは、 Line Inputステートメントでは、1行毎にデータの取得はできませんよ!! そもそも1行がどこまでなのかがわかりませんし・・・。 Line Input ステーメントは区切り(&H0D0A)コードがあるという前提です。 区切りコードのないデータは、バイナリモードかランダムモードでOpenして、 Getステートメントで読み込みが一般的です。 データ内にバイナリデータもある可能性があるなら、尚のことです。 Line Inputでは、正確にバイナリデータを取得することは難しいですから・・・。 他にもADOのStreamオブジェクトを使う方法もあります。 時間がある時に調べておけば役に立ちます。 >VBAですと2分ぐらいというところでしょうか。 Javaの方がVBAより、処理速度は速いはずですが、工夫をすれば、少しでもその差を縮められる という例として、今回、同じ処理をするコードをコードを変えて何度か投稿しました。 よって、ファイルの種類が違ってもVBAでも工夫しだいで2分かかる処理速度を縮めることは 出来るかもしれませんよ!! >速度よりは安全に処理できるかという方が大事だと >思いますけど。 これは、賛成です。但し、処理速度の速いアルゴリズムを知っていて、習得した上で 検討した結果、わかりやすいアルゴリズムや簡単な手法を選択する という判断であるならばですよね!! 勉強をしない免罪符にはしないでください ichinose ---- 失礼しました。 Line インプットステートメントを よく知らずに発言してしまいました。 そもそもichinoseさんなら、コード提示頂いてる時点で 気づいてますから。 それと、どんなバイナリデータが 混在するか分かりませんからね。 今は、ソースコードの勉強もそうですが データ構造を勉強したいと思っております。 因みに工夫すれば安全に速く処理出来る方法も あるかと思いますが VBAは、難易度が高いのとアップデートがない分? 現状は自作するのは非常に難しいです。 それと以前在籍してた プログラマーが KEIS等扱うgetステートメントより AdodbによるCSV入出力の方が 一度に読み込んで書き出す作業は 心配と言ってたのですが ichinoseさんはこの発言について なにか分かりますでしょうか? フェンダー ---- >VBAは、難易度が高いのとアップデートがない分? >現状は自作するのは非常に難しいです。 この点について・・・。 >アップデートがない分? この意味がわかりませんが・・。 私も独学でプログラミングを始めたのであれば、おそらくは、誰も教えてくれないので 中々ファイルI/Oの高速化の自作なんて発想にはなりません。 が、今はこのような掲示板があるのですから、色んな手法をご存じの方がいるはずです。 このスレッドでも >3 Get Putの使用頻度 という投稿で記述しましたが、 Get PUTの使用頻度を減らすことを考える と申し上げました。 そのために >レコードとバッファの関係をコード内でシミュレート と記述しました。 >一応JAVAでは、Bufferクラスを使用して1行ずつ読み書き対応出来るようにして >処理は早くなってますが このBufferクラスは、1行で読み込めるから処理が速いのではなく、直接ファイルにアクセスする 回数をこの中では極端に少なくしているからです。 オブジェクトという形式で中身を隠蔽していて指定バイトで読み込み書き込みという インターフェースになっているので、一見、 bos.writeでこのコードの回数分ファイルに書き込みしているようにみえますが、書き込み先は 実際は、ファイルではないと思いますよ。 最後に投稿したコードは、これの真似事みたいなコードを投稿したつもりです。 もっと、高速な方法、VBAで自作のオブジェクトを作成すれば、もっとスッキリしたコードに なる可能性はあります。 まずは、得意なJAVAのこのBufferクラスで何をしているから高速なのかを探ってみては いかがですか? >AdodbによるCSV入出力の方が >一度に読み込んで書き出す作業は >心配と言ってたのですが 扱うCSVファイルの容量の問題(ファイル容量が大きい)ではないですか? それから派生する問題は、試してみなければわかりませんね!! >CSVより CSV入出力の方が内容が濃いのですが CSVの入出力の具体的な内容にもよりますし・・・。 但し、前回投稿の >他にもADOのStreamオブジェクト は、大丈夫だと思いますけどねえ 実は、これを使ってのSample.DAT〜Sample.csvの作成は、私の環境で7〜8秒でした。 インタフェースは、BufferedInputStream等に似ているので扱いやすいかもしれませんよ!! もっともこれほど速くはないですが・・・。 以上です。 ichinose ---- アドバイスどうもありがとうございます。 ひとまずこのスレのおかげで 表題の土台は解決したと思います。 色々な忠告を受け止めて 勉強してみます。 このスレ長いですよね。 どうもありがとうございました。 (フェンダー) ---- こちらはエクセル学校でありますので こういった説明はしないつもりでしたが ご報告いたします。 >一応JAVAでは、Bufferクラスを使用して1行ずつ読み書き対応出来るようにして >処理は早くなってますが こちらは細かく説明しなかったのですが サンプル提示したものとは違います。 ichinoseさんが引っかかった部分は CSV入出力で、実績があるソースコード(今回は標題と関係ありませんから提示してませ ん)で BufferedReaderクラスには1行ずつデータを読み込む、 readLineメソッドが用意されていて writeメソッドによりデータの書き込み処理を行なっています。 今回、使用し提示したソースコードはバイナリ入出力の ソースコードになりますので 1行ずつ読み書き 1行ずつ読み そして書くの手順では実行されてないです。 こちらの処理方法手順は記載しません。 >一応JAVAでは、Bufferクラスを使用して1行ずつ読み書き対応出来るようにして >処理は早くなってますが とは関係ないことだけご報告いたします。 提示したサンプルコードについては 検証段階で実績はありません。 それと他にも 紛らわしい情報や 色々と疑問がある場合もあるかと思いますが ご了承ください。 標題は一段落してますので見て頂くだけで返信はいりません。 今回の件についてはご報告させていただきました。 (フェンダー) ---- > 今回、使用し提示したソースコードはバイナリ入出力の >ソースコードになりますので >1行ずつ読み書き >1行ずつ読み >そして書くの手順では実行されてないです それは、コードを拝見したのでわかっているつもりです。 >CSV入出力で、実績があるソースコード(今回は標題と関係ありませんから提示してませ ん)で >BufferedReaderクラスには1行ずつデータを読み込む、 >readLineメソッドが用意されていて どっちにしろ、私が申し上げたいことは同じなんですよ!! BufferedReaderクラスのreadLineメソッドは、 >1行で読み込めるから処理が速いのではなく、直接ファイルにアクセスする >回数をこの中では極端に少なくしているからです。 と前回投稿と同じことは言えるのです。 この中のしくみは、 何度も繰り返しますが、 ファイルへの読み込み、書き込みを減らすことを考えた手法がとられているのです。 つまり、何回も申し上げているVBAで言い換えれば、 >Get PUTの使用頻度を減らすことを考える なのです。 ですから、 >このBufferクラスで何をしているから高速なのかを探ってみては と記述しました。私が申し上げたいのは ここなのです。 http://www.javaroad.jp/java_io4.htm ここの概要に私が申し上げたようなことがかいてありますから、読んでみてください。 そして、理解したら、VBAでコードを書くなら、同じようなクラスを作ってみては? という提案です。 このスレッドでの私が言いたかったことですから、返信不要と仰っていましたが、 敢えて投稿しました。 ichinose ---- >1行で読み込めるから処理が速いのではなく、直接ファイルにアクセスする >回数をこの中では極端に少なくしているからです。 こちらもわざわざ細かく説明しなかったのですが http://www.javaroad.jp/java_io4.htm もJAVAを始める以前からチェックしていたサイトで 把握はしていて使用していました。 もちろんサイトだけチェックするぐらいでは ソースも書けないので、勉強している段階になりますが。 勉強段階ですし、わざわざうんちくを語るように細かく説明するつもりはありませんでしたので 下記のような >一応JAVAでは、Bufferクラスを使用して1行ずつ読み書き対応出来るようにして >処理は早くなってますが と失言をしてしまったのが始まりですが・・・ 以後気をつけます。 そもそもJAVAにはこういった効率がよく入出力できる クラスがあるというのを知ってから 使用するのがきっかけになりますから。 文字コードの指定もクラスによって自由に変更出来たりと。 まあ開発統合環境でも文字コードは指定できますが・・・ あまり適当に喋りますと失言が出てしまいますのでこの辺で・・・ >そして、理解したら、VBAでコードを書くなら、同じようなクラスを作ってみては? >という提案です。 結論から申し上げますと、今回の開発はJAVAで行うことにしました。 VBAでクラスを考える時間で、今後想定される仕様の 勉強に時間をあてた方が良いかと思いまして・・・ 色々、サンプル提示していただいたVBAコードは 他のアイデアでも参考に出来ますので大変勉強になりました。 フィールドごとに考えなければいけないことが ありましたら、 アルゴリズムについてのアドバイスを 頂けたら助かります。 その時はどうぞ宜しくお願いいたします。 (フェンダー) ...
https://www.excel.studio-kazu.jp/wiki/kazuwiki/201308/20130808161622.txt - [detail] - similar
PREV NEXT
Powered by Hyper Estraier 1.4.13, with 97037 documents and 608190 words.

訪問者:カウンタValid HTML 4.01 Transitional