VB6初心者のたえです。
ネットワーク上からFileSyStemObjectを使ってファイルをコピー
しているのですが、ファイルが大きいのと、ネットワーク環境が悪いので、
エクスプローラから、ファイルをコピーしたときの「コピーしています。」
というプログレスバーを表示させたいのですが、どのようなことをしたら
よいでしょうか?
宜しくお願い致します。
小さいファイルをたくさんコピーしてるなら、ループの中でプログレスバー
の値を変更していけば良いですが、1つの大きなファイルの場合、ファイルの
コピー終了まで待機している処理と、一定時間ごとにプログレスバーを更新する
処理の2つを制御しなければならないでしょう。
これを『マルチスレッド』処理と呼びます。まずはこのキーワードでヘルプや
過去ログ検索してみて下さい。
単一プロセッサのコンピュータ上のマルチスレッドで、予期しない結果になる
場合があります。何に注意すべきか分からないうちはマルチスレッド処理を
使うべきではありません。
シングルスレッドでファイルのコピーとプログラスバーの制御を同時に行うなら、
・FileSyStemObjectではなく、BinaryモードでのOpen〜Closeでファイルをコピー。
・コピー前にファイルサイズを取得しておく。
・ファイルを読み込む時に使うバッファサイズとファイルサイズから、
何回読み書きすれば完了となるか算出しておく。
・「元ファイルを読み→先ファイルへ書き→プログラスバーの更新」
を繰り返す。
よぅな手順になるかと思います。
もとい。
プログラス→プログレス
# 何をまちがえているんだ私は(T−T)
いっそSHFileOperation(API)つかったら?
みなさん、回答ありがとうございます。
>・FileSyStemObjectではなく、BinaryモードでのOpen〜Close
> でファイルをコピー。
>・コピー前にファイルサイズを取得しておく。
>・ファイルを読み込む時に使うバッファサイズとファイルサイズから、
> 何回読み書きすれば完了となるか算出しておく。
>・「元ファイルを読み→先ファイルへ書き→プログラスバーの更新」
> を繰り返す。
早速サルベージさんの手順でやってみます。
できましたらUPしますので、採点の程
宜しくお願い致します。
>できましたらUPしますので、採点の程と・・・・
とはいったものの、ファイルは1つで、MDBファイルです。
しかもMDBを開くシステム権限がありません。
このような形でも
Open〜Closeはできるのでしょうか?
> しかもMDBを開くシステム権限がありません。
そのファイルを、エクスプローラ等で手動でコピーできるだけの
権限があれば十分です。
データベースとしてADO/DAO等で開くのであれば、確かに権限が必要ですが、
バイナリファイルとして読み込む分には、データベース権限は不要です。
おはようございます。
たえです。
魔界の仮面弁士さんレスありがとうございました。
早速、がんばってやってみます。
こんにちは、たえです。
いつもお世話になっています。
>・ファイルを読み込む時に使うバッファサイズとファイルサイズから、
> 何回読み書きすれば完了となるか算出しておく。
ここの部分で行き詰まってしまいまいました。バッファサイズは
どのようにして求めたらよいでしょうか?
なぜOpen〜Closeして、コピーするのでしょうか?
途中までやってみました。
ご指導願えたら幸いです。
Option Explicit
Sub main()
Dim i As Long, j As Long
Dim s As String, MotoF As String, SakiF As String
Dim f As String
MotoF = "C:\1\TEST.mdb"
j = InStrRev(MotoF, "\")
s = Mid$(MotoF, j + 1)
SakiF = "D:\1\" & s
Open "C:\1\TEST.mdb" For Input As #1
Input #1, f
i = FileLen(MotoF) 'ファイルサイズを求める
FileCopy MotoF, SakiF
Close #1
'Debug.Print f
End Sub
というか・・・
>FileSyStemObjectではなく、BinaryモードでのOpen〜Closeでファイルをコピー。
はFileSyStemObjectではなく、BinaryモードでのOpen〜Closeでファイルをコピーを行いましょう!という意味じゃない?
んでその前には必ずファイルサイズ(=プログレスのMAX値)を取っておかないとできないよ!
分母が決まったら分子を決めてあげれば何回の処理でおわるかわかるよね!
じゃぁその計算結果を当てはめてループできるよね!ということだと思う
あと#1の固定じゃなくて
FreeFileを使うべし・・・
たえです。
葉月αさん、ありがとうございました。
済みません。初心者で、コピーするところで困っています。
同じところにコピーされてしまいます。しかもファイルサイズがどんどん
大きくなり、MDBファイルも開けないです。
コピー先にどうやればよいでしょうか?
宜しくお願いします。
Option Explicit
Sub main()
Dim i As Long, ii As Long, j As Long, FileNO1 As Long
Dim s As String, MotoF As String, SakiF As String
Dim f As Long
MotoF = "C:\1\TEST.mdb"
j = InStrRev(MotoF, "\")
s = Mid$(MotoF, j + 1)
SakiF = "D:\1\" & s
FileNO1 = FreeFile()
Open MotoF For Binary Access Read Write As #FileNO1
i = FileLen(MotoF) 'ファイルサイズ
For ii = 1 To i
f = ii
Get #FileNO1, , f
Put #FileNO1, , SakiF
Next ii
Close #FileNO1
End Sub
それなりのコードを組んでいるんだからそれぞれの
ステートメントなり関数について使い方を調べた上で
使っているんですよね?
一度上記ソースに、一行ずつこの行で何をやっているつもり
なのか全て記載してみて下さい。
たえです。
0123さんありがとうございます。
コードにコメントしてみました。
ご教授宜しくお願いします。
Option Explicit
Sub main()
Dim i As Long, ii As Long, j As Long, FileNO1 As Long
Dim s As String, MotoF As String, SakiF As String
Dim f As Long
'コピー元ファイル
MotoF = "C:\1\TEST.mdb"
'後ろから数えて\がどこにあるのかを数える。
j = InStrRev(MotoF, "\")
'ファイル名を取得
s = Mid$(MotoF, j + 1)
'コピー先ファイル
SakiF = "D:\1\" & s
'使用可能なファイル番号を返す
FileNO1 = FreeFile()
'バイナリモードでファイルオープン
Open MotoF For Binary Access Read Write As #FileNO1
'ファイルサイズ取得
i = FileLen(MotoF)
'ファイルサイズをループ
For ii = 1 To i
f = ii
Get #FileNO1, , f 'データを読込
Put #FileNO1, , SakiF 'コピー先にデータを書込
Next ii
Close #FileNO1 '閉じる
End Sub
>Open MotoF For Binary Access Read Write As #FileNO1
Openの説明は読みましたか?Binaryモードで開くとき、既にファイルが存在
する場合はどうなりますか?
コピー先のファイルはどこで開いていますか?
>Get #FileNO1, , f 'データを読込
ここで読み込んでいるのは何バイトですか?
>Put #FileNO1, , SakiF 'コピー先にデータを書込
コピー先のファイル番号はコピー元と一緒ですか?
書き出しているのは何ですか?
そりゃ大きくなるとか、同じところにコピーされる罠 藁
貴方はどこのファイルをコピー元としたいのですか?
貴方はどこのファイルをコピー先としたいのですか?
コピー先の指定はどこですか?
ファイルナンバーは固定で一つ取得するものではなく
各アクセスしたいファイルに対して取得する値です
だから・・・
>Get #FileNO1, , f 'データを読込
でデータを読込んでいるのかも知れませんが
>Put #FileNO1, , SakiF 'コピー先にデータを書込
ここの意味を調べてみてください・・・
ちなみにそのMDBファイルは確実に破損しています
及び、そのソースだと破損します
あのルーチンが完成してからの話ですが、コピー先に同名ファイルがあるときに
どのような処理にするのか考える必要がありますよ。
必ず削除して再生成?
ユーザーへ問い合わせしてから処理?
既存ファイルを別名にコピー後に新規作成?
たえです。こんにちは
0123さんレスありがとうございました。他の皆様もありがとうございます。
>Openの説明は読みましたか?Binaryモードで開くとき、既にファイルが存在
>する場合はどうなりますか?
はい、Openステートメントを読んでみました。
MSDNより
>引数 pathname に指定したファイルが存在しない場合、ファイルを開くときに
>追加モード (Append)、バイナリ モード (Binary)、出力モード (Output)、
>またはランダム アクセス モード (Random) のいずれかのモードが指定されている場合、
>新規に作成されて開きます。
と書いてありました。ファイルが存在しない場合は見つけれませんでした。
>ここで読み込んでいるのは何バイトですか?
1バイトです。
>コピー先のファイル番号はコピー元と一緒ですか?
>書き出しているのは何ですか?
ソースを書き換えましたので、ご覧頂けないでしょうか?
レスを頂いたみなさんのお返事は改めてさせて
頂きます。いっぱいいっぱいですので、ちょっと待って下さい。
下のようなかたちにしたところ、
実行時エラー54
ファイルモードが不正です。
と
Put #FileNO2, , f 'コピー先にデータを書込
ここで、エラーになります。
自分の中では、少し進歩しました。
エラーは出ましたけど、目的のところにゼロKBの開かないMDBが
コピーできました。
まだまだ先は遠いですけど、もう少しご教授願えたらうれしいです。
Option Explicit
Sub main()
Dim i As Long, ii As Long, j As Long, FileNO1 As Long, FileNO2 As Long
Dim s As String, MotoF As String, SakiF As String
Dim f As Byte
'コピー元ファイル
MotoF = "C:\1\TEST.mdb"
'後ろから数えて\がどこにあるのかを数える。
j = InStrRev(MotoF, "\")
'ファイル名を取得
s = Mid$(MotoF, j + 1)
'コピー先ファイル
SakiF = "D:\1\" & s
'使用可能なファイル番号を返す
FileNO1 = FreeFile()
'バイナリモードでファイルオープン
Open MotoF For Binary Access Read Write As #FileNO1
FileNO2 = FreeFile()
Open SakiF For Output As #FileNO2
'ファイルサイズ取得
i = FileLen(MotoF)
'ファイルサイズをループ
For ii = 1 To i
f = ii
Get #FileNO1, , f 'データを読込
Put #FileNO2, , f 'コピー先にデータを書込
Next ii
Close #FileNO2 '閉じる
Close #FileNO1 '閉じる
End Sub
>ファイルモードが不正です。
> Open SakiF For Output As #FileNO2
> ^^^^^^
オープンのモードがOutputになっていますよ。
Binaryで開いてみてください。
> f = ii
Forの中で使用してる↑が意味のないコードに思えますが・・・
たえです。
うわあ、感動です。
ありがとうございました。
これから、プログレスバーとコピー先に同名ファイルがあるときなど
いろいろありますので、これからもご指導願います。
ずうずうしいですが、まだ解決しません。
宜しくお願いします。
Win32APIのSHFileOperationを使えばいいとおもうけど・・・。
ちなみにmdbファイルをコピーするのであれば、コピーの前に
最適化を行ってファイルサイズを小さくすることをお勧めします。
下のページにサンプルがあります。
http://www.moug.net/skillup/nksw/nksw14-03.htm?PRINT
>とはいったものの、ファイルは1つで、MDBファイルです。
>しかもMDBを開くシステム権限がありません。
権限がないと最適化できません。失礼。
たえです。こんにちは
>必ず削除して再生成?
この方法にしました。
shunさんリンク先見ました。
すごいですね。
APIをまだほとんど理解していない私には、
まだ壁ですけど。
皆様のおかげでできましたので、UPします。
採点の程お願い致します。
なにか諸注意などありましたら、宜しくお願い
します。
Sub コピー()
Dim i As Long, ii As Long, j As Long, FileNO1 As Long, FileNO2 As Long
Dim s As String, MotoF As String, SakiF As String
Dim f As Byte
MotoF = "C:\1\TEST.mdb"
j = InStrRev(MotoF, "\")
s = Mid$(MotoF, j + 1)
SakiF = "D:\1\" & s
If Dir(SakiF) <> "" Then Kill SakiF
FileNO1 = FreeFile()
Open MotoF For Binary Access Read Write As #FileNO1
FileNO2 = FreeFile()
Open SakiF For Binary Access Read Write As #FileNO2
i = FileLen(MotoF)
With Form1.ProgressBar1
.Max = i
.Min = 0
.Visible = True
End With
For ii = 1 To i
Form1.ProgressBar1.Value = ii
Get #FileNO1, , f
Put #FileNO2, , f
Next ii
Close #FileNO2
Close #FileNO1
Unload Form1
End Sub
>必ず削除して再生成?
↑と書いたもののもう少し工夫した方がいいかも。
例えばコピーが失敗した時に昔のものが既に消えていると悲しいですね。
(仕様にもよるのでしょうが・・・)
あとはOn Errorとか使用してエラー対策をしましょう。
Form1.ProgressBar1のForm1は使用しないほうがいいですよ。
自分を表すならMeかな。
Unload Meみたいに。
'テストコード
'Form1, Form2を用意してForm1にコマンドボタン、Form2にラベルを貼り付ける。
'コマンドボタンをクリックした時にForm2を表示してラベルにテストを表示できるか?
'Form1側のコード
'Command1ボタンのクリック
Private Sub Command1_Click()
Dim frm2 As New Form2
frm2.Show
End Sub
'Form2側のコード
Private Sub Form_Load()
Form2.Label1.Caption = "てすと"
End Sub
ツイート | ![]() |