ファイルをコピーしているときのプログレスバーを出すには?


たえ  2005-06-14 19:52:15  No: 122589

VB6初心者のたえです。

ネットワーク上からFileSyStemObjectを使ってファイルをコピー
しているのですが、ファイルが大きいのと、ネットワーク環境が悪いので、
エクスプローラから、ファイルをコピーしたときの「コピーしています。」
というプログレスバーを表示させたいのですが、どのようなことをしたら
よいでしょうか?

宜しくお願い致します。


特攻隊長まるるう  2005-06-14 20:30:31  No: 122590

小さいファイルをたくさんコピーしてるなら、ループの中でプログレスバー
の値を変更していけば良いですが、1つの大きなファイルの場合、ファイルの
コピー終了まで待機している処理と、一定時間ごとにプログレスバーを更新する
処理の2つを制御しなければならないでしょう。
これを『マルチスレッド』処理と呼びます。まずはこのキーワードでヘルプや
過去ログ検索してみて下さい。

単一プロセッサのコンピュータ上のマルチスレッドで、予期しない結果になる
場合があります。何に注意すべきか分からないうちはマルチスレッド処理を
使うべきではありません。


さるべーじ  2005-06-14 20:43:54  No: 122591

シングルスレッドでファイルのコピーとプログラスバーの制御を同時に行うなら、

・FileSyStemObjectではなく、BinaryモードでのOpen〜Closeでファイルをコピー。
・コピー前にファイルサイズを取得しておく。
・ファイルを読み込む時に使うバッファサイズとファイルサイズから、
  何回読み書きすれば完了となるか算出しておく。
・「元ファイルを読み→先ファイルへ書き→プログラスバーの更新」
  を繰り返す。

よぅな手順になるかと思います。


さるべーじ  2005-06-14 20:45:12  No: 122592

もとい。
    プログラス→プログレス

# 何をまちがえているんだ私は(T−T)


Say  2005-06-14 21:28:28  No: 122593

いっそSHFileOperation(API)つかったら?


たえ  2005-06-15 01:55:09  No: 122594

みなさん、回答ありがとうございます。

>・FileSyStemObjectではなく、BinaryモードでのOpen〜Close
>  でファイルをコピー。
>・コピー前にファイルサイズを取得しておく。
>・ファイルを読み込む時に使うバッファサイズとファイルサイズから、
>  何回読み書きすれば完了となるか算出しておく。
>・「元ファイルを読み→先ファイルへ書き→プログラスバーの更新」
>  を繰り返す。

早速サルベージさんの手順でやってみます。
できましたらUPしますので、採点の程
宜しくお願い致します。


たえ  2005-06-15 04:02:36  No: 122595

>できましたらUPしますので、採点の程と・・・・
とはいったものの、ファイルは1つで、MDBファイルです。
しかもMDBを開くシステム権限がありません。

このような形でも
Open〜Closeはできるのでしょうか?


魔界の仮面弁士  2005-06-15 05:03:24  No: 122596

> しかもMDBを開くシステム権限がありません。

そのファイルを、エクスプローラ等で手動でコピーできるだけの
権限があれば十分です。

データベースとしてADO/DAO等で開くのであれば、確かに権限が必要ですが、
バイナリファイルとして読み込む分には、データベース権限は不要です。


たえ  2005-06-15 17:25:52  No: 122597

おはようございます。
たえです。

魔界の仮面弁士さんレスありがとうございました。
早速、がんばってやってみます。


たえ  2005-06-17 00:40:00  No: 122598

こんにちは、たえです。
いつもお世話になっています。

>・ファイルを読み込む時に使うバッファサイズとファイルサイズから、
>  何回読み書きすれば完了となるか算出しておく。

ここの部分で行き詰まってしまいまいました。バッファサイズは
どのようにして求めたらよいでしょうか?

なぜ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


葉月α  2005-06-17 01:11:43  No: 122599

というか・・・
>FileSyStemObjectではなく、BinaryモードでのOpen〜Closeでファイルをコピー。
はFileSyStemObjectではなく、BinaryモードでのOpen〜Closeでファイルをコピーを行いましょう!という意味じゃない?

んでその前には必ずファイルサイズ(=プログレスのMAX値)を取っておかないとできないよ!

分母が決まったら分子を決めてあげれば何回の処理でおわるかわかるよね!

じゃぁその計算結果を当てはめてループできるよね!ということだと思う


葉月  2005-06-17 01:13:43  No: 122600

あと#1の固定じゃなくて
FreeFileを使うべし・・・


たえ  2005-06-17 03:36:48  No: 122601

たえです。

葉月αさん、ありがとうございました。

済みません。初心者で、コピーするところで困っています。
同じところにコピーされてしまいます。しかもファイルサイズがどんどん
大きくなり、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  2005-06-17 03:57:21  No: 122602

それなりのコードを組んでいるんだからそれぞれの
ステートメントなり関数について使い方を調べた上で
使っているんですよね?

一度上記ソースに、一行ずつこの行で何をやっているつもり
なのか全て記載してみて下さい。


たえ  2005-06-17 04:16:19  No: 122603

たえです。
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


0123  2005-06-17 05:13:19  No: 122604

>Open MotoF For Binary Access Read Write As #FileNO1
Openの説明は読みましたか?Binaryモードで開くとき、既にファイルが存在
する場合はどうなりますか?
コピー先のファイルはどこで開いていますか?

>Get #FileNO1, , f 'データを読込
ここで読み込んでいるのは何バイトですか?

>Put #FileNO1, , SakiF  'コピー先にデータを書込
コピー先のファイル番号はコピー元と一緒ですか?
書き出しているのは何ですか?


葉月α  2005-06-17 17:56:38  No: 122605

そりゃ大きくなるとか、同じところにコピーされる罠  藁
貴方はどこのファイルをコピー元としたいのですか?
貴方はどこのファイルをコピー先としたいのですか?

コピー先の指定はどこですか?
ファイルナンバーは固定で一つ取得するものではなく
各アクセスしたいファイルに対して取得する値です

だから・・・
>Get #FileNO1, , f 'データを読込
でデータを読込んでいるのかも知れませんが

>Put #FileNO1, , SakiF  'コピー先にデータを書込
ここの意味を調べてみてください・・・


葉月α  2005-06-17 17:58:38  No: 122606

ちなみにそのMDBファイルは確実に破損しています
及び、そのソースだと破損します


GOD  2005-06-17 19:32:36  No: 122607

あのルーチンが完成してからの話ですが、コピー先に同名ファイルがあるときに
どのような処理にするのか考える必要がありますよ。

必ず削除して再生成?
ユーザーへ問い合わせしてから処理?
既存ファイルを別名にコピー後に新規作成?


たえ  2005-06-18 00:54:26  No: 122608

たえです。こんにちは

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


GOD  2005-06-18 01:59:09  No: 122609

>ファイルモードが不正です。
>       Open SakiF For Output As #FileNO2
>                      ^^^^^^
オープンのモードがOutputになっていますよ。
Binaryで開いてみてください。

>             f = ii
Forの中で使用してる↑が意味のないコードに思えますが・・・


たえ  2005-06-18 03:06:43  No: 122610

たえです。

うわあ、感動です。
ありがとうございました。

これから、プログレスバーとコピー先に同名ファイルがあるときなど
いろいろありますので、これからもご指導願います。
ずうずうしいですが、まだ解決しません。

宜しくお願いします。


shun  2005-06-21 01:56:29  No: 122611

Win32APIのSHFileOperationを使えばいいとおもうけど・・・。
ちなみにmdbファイルをコピーするのであれば、コピーの前に
最適化を行ってファイルサイズを小さくすることをお勧めします。
下のページにサンプルがあります。
http://www.moug.net/skillup/nksw/nksw14-03.htm?PRINT


shun  2005-06-21 01:58:52  No: 122612

>とはいったものの、ファイルは1つで、MDBファイルです。
>しかもMDBを開くシステム権限がありません。

権限がないと最適化できません。失礼。


たえ  2005-06-21 22:02:37  No: 122613

たえです。こんにちは

>必ず削除して再生成?
この方法にしました。

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


GOD  2005-06-21 22:21:37  No: 122614

>必ず削除して再生成?
↑と書いたもののもう少し工夫した方がいいかも。
例えばコピーが失敗した時に昔のものが既に消えていると悲しいですね。
(仕様にもよるのでしょうが・・・)

あとは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


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加