ファイルをsftpサーバーにアップロードする単純なc#コンソールアプリを書いています。ただし、ファイルの量は膨大です。アップロードするファイルの割合、またはアップロードするファイルの総数から既にアップロードされているファイルの数だけを表示したいと思います。
最初に、すべてのファイルとファイルの総数を取得します。
string[] filePath = Directory.GetFiles(path, "*");
totalCount = filePath.Length;
次に、ファイルをループし、foreachループで1つずつアップロードします。
foreach(string file in filePath)
{
string FileName = Path.GetFileName(file);
//copy the files
oSftp.Put(LocalDirectory + "/" + FileName, _ftpDirectory + "/" + FileName);
//Console.WriteLine("Uploading file..." + FileName);
drawTextProgressBar(0, totalCount);
}
Foreachループには、問題のある進行状況バーがあります。正しく表示されません。
private static void drawTextProgressBar(int progress, int total)
{
//draw empty progress bar
Console.CursorLeft = 0;
Console.Write("["); //start
Console.CursorLeft = 32;
Console.Write("]"); //end
Console.CursorLeft = 1;
float onechunk = 30.0f / total;
//draw filled part
int position = 1;
for (int i = 0; i < onechunk * progress; i++)
{
Console.BackgroundColor = ConsoleColor.Gray;
Console.CursorLeft = position++;
Console.Write(" ");
}
//draw unfilled part
for (int i = position; i <= 31 ; i++)
{
Console.BackgroundColor = ConsoleColor.Green;
Console.CursorLeft = position++;
Console.Write(" ");
}
//draw totals
Console.CursorLeft = 35;
Console.BackgroundColor = ConsoleColor.Black;
Console.Write(progress.ToString() + " of " + total.ToString() + " "); //blanks at the end remove any excess
}
出力は1943年のちょうど[0]です
ここで何が間違っていますか?
編集:
XMLファイルをロードおよびエクスポートしているときにプログレスバーを表示しようとしています。しかし、それはループを通過しています。最初のラウンドが終了すると、2番目のラウンドに進みます。
string[] xmlFilePath = Directory.GetFiles(xmlFullpath, "*.xml");
Console.WriteLine("Loading XML files...");
foreach (string file in xmlFilePath)
{
for (int i = 0; i < xmlFilePath.Length; i++)
{
//ExportXml(file, styleSheet);
drawTextProgressBar(i, xmlCount);
count++;
}
}
Forループが終了することはありません...提案はありますか?
この行はあなたの問題です:
drawTextProgressBar(0, totalCount);
繰り返しごとに進捗がゼロであると言っているので、これを増やす必要があります。代わりにforループを使用することもできます。
for (int i = 0; i < filePath.length; i++)
{
string FileName = Path.GetFileName(filePath[i]);
//copy the files
oSftp.Put(LocalDirectory + "/" + FileName, _ftpDirectory + "/" + FileName);
//Console.WriteLine("Uploading file..." + FileName);
drawTextProgressBar(i, totalCount);
}
コンソールの進行状況バーも探していました。必要なことをするものが見つからなかったので、自分でロールバックすることにしました。 ソースコードはここをクリック (MITライセンス)。
特徴:
リダイレクト出力で動作します
コンソールアプリケーションの出力(たとえば、Program.exe > myfile.txt
)をリダイレクトすると、ほとんどの実装は例外でクラッシュします。 Console.CursorLeft
およびConsole.SetCursorPosition()
はリダイレクトされた出力をサポートしていないためです。
実装IProgress<double>
これにより、[0..1]の範囲の進行状況を報告する非同期操作で進行状況バーを使用できます。
スレッドセーフ
高速
Console
クラスは、そのひどいパフォーマンスで有名です。呼び出しが多すぎると、アプリケーションの速度が低下します。このクラスは、進行状況の更新を報告する頻度に関係なく、1秒あたり8回だけ呼び出しを実行します。
次のように使用します。
Console.Write("Performing some task... ");
using (var progress = new ProgressBar()) {
for (int i = 0; i <= 100; i++) {
progress.Report((double) i / 100);
Thread.Sleep(20);
}
}
Console.WriteLine("Done.");
これは古いスレッドであり、セルフプロモーションをおologiesびしますが、最近、nuget Goblinfactory.Konsole で利用可能なオープンソースコンソールライブラリを作成しました。メインスレッドをブロックしないものを必要とするこのページに新しい。
ダウンロードとタスクを並行して開始し、他のタスクを続行できるため、上記の回答とは多少異なります。
乾杯、これが役立つことを願って
A
var t1 = Task.Run(()=> {
var p = new ProgressBar("downloading music",10);
... do stuff
});
var t2 = Task.Run(()=> {
var p = new ProgressBar("downloading video",10);
... do stuff
});
var t3 = Task.Run(()=> {
var p = new ProgressBar("starting server",10);
... do stuff .. calling p.Refresh(n);
});
Task.WaitAll(new [] { t1,t2,t3 }, 20000);
Console.WriteLine("all done.");
このタイプの出力を提供します
Nugetパッケージには、完全なクリッピングとラッピングのサポート、およびPrintAt
およびその他のさまざまな有用なクラスを使用して、コンソールのウィンドウセクションに書き込むためのユーティリティも含まれています。
Nugetパッケージを作成したのは、ビルドおよびopsコンソールスクリプトとユーティリティを作成するたびに、多くの一般的なコンソールルーチンを常に記述していたためです。
複数のファイルをダウンロードしていた場合、各スレッドの画面にConsole.Write
をゆっくりと使用し、画面上のインターリーブされた出力を読みやすくするためにさまざまなトリックを試してみました。異なる色または数字。最終的には、さまざまなスレッドからの出力をさまざまなウィンドウに簡単に印刷できるようにウィンドウ処理ライブラリを作成し、ユーティリティスクリプトの大量の定型コードを削減しました。
たとえば、このコードは、
var con = new Window(200,50);
con.WriteLine("starting client server demo");
var client = new Window(1, 4, 20, 20, ConsoleColor.Gray, ConsoleColor.DarkBlue, con);
var server = new Window(25, 4, 20, 20, con);
client.WriteLine("CLIENT");
client.WriteLine("------");
server.WriteLine("SERVER");
server.WriteLine("------");
client.WriteLine("<-- PUT some long text to show wrapping");
server.WriteLine(ConsoleColor.DarkYellow, "--> PUT some long text to show wrapping");
server.WriteLine(ConsoleColor.Red, "<-- 404|Not Found|some long text to show wrapping|");
client.WriteLine(ConsoleColor.Red, "--> 404|Not Found|some long text to show wrapping|");
con.WriteLine("starting names demo");
// let's open a window with a box around it by using Window.Open
var names = Window.Open(50, 4, 40, 10, "names");
TestData.MakeNames(40).OrderByDescending(n => n).ToList()
.ForEach(n => names.WriteLine(n));
con.WriteLine("starting numbers demo");
var numbers = Window.Open(50, 15, 40, 10, "numbers",
LineThickNess.Double,ConsoleColor.White,ConsoleColor.Blue);
Enumerable.Range(1,200).ToList()
.ForEach(i => numbers.WriteLine(i.ToString())); // shows scrolling
これを作り出す
ウィンドウに書き込むのと同じくらい簡単に、ウィンドウ内に進行状況バーを作成することもできます。 (ミックスアンドマッチ)。
ProgressBar
メソッドをコピーして貼り付けました。受け入れられた答えが述べたように、あなたのエラーがループにあったからです。ただし、ProgressBar
メソッドにもいくつかの構文エラーがあります。これが作業バージョンです。わずかに変更されました。
private static void ProgressBar(int progress, int tot)
{
//draw empty progress bar
Console.CursorLeft = 0;
Console.Write("["); //start
Console.CursorLeft = 32;
Console.Write("]"); //end
Console.CursorLeft = 1;
float onechunk = 30.0f / tot;
//draw filled part
int position = 1;
for (int i = 0; i < onechunk * progress; i++)
{
Console.BackgroundColor = ConsoleColor.Green;
Console.CursorLeft = position++;
Console.Write(" ");
}
//draw unfilled part
for (int i = position; i <= 31; i++)
{
Console.BackgroundColor = ConsoleColor.Gray;
Console.CursorLeft = position++;
Console.Write(" ");
}
//draw totals
Console.CursorLeft = 35;
Console.BackgroundColor = ConsoleColor.Black;
Console.Write(progress.ToString() + " of " + tot.ToString() + " "); //blanks at the end remove any excess
}
@ Daniel-wolfにはより良いアプローチがあることに注意してください: https://stackoverflow.com/a/31193455/169714
元のポスターの進行状況バーは非常に気に入りましたが、特定の進行状況/合計アイテムの組み合わせで進行状況が正しく表示されないことがわかりました。たとえば、次のコードは正しく描画されず、進行状況バーの最後に余分な灰色のブロックが残ります。
drawTextProgressBar(4114, 4114)
上記の問題を修正する不必要なループを削除するために、描画コードの一部を再編集し、かなり高速化しました:
public static void drawTextProgressBar(string stepDescription, int progress, int total)
{
int totalChunks = 30;
//draw empty progress bar
Console.CursorLeft = 0;
Console.Write("["); //start
Console.CursorLeft = totalChunks + 1;
Console.Write("]"); //end
Console.CursorLeft = 1;
double pctComplete = Convert.ToDouble(progress) / total;
int numChunksComplete = Convert.ToInt16(totalChunks * pctComplete);
//draw completed chunks
Console.BackgroundColor = ConsoleColor.Green;
Console.Write("".PadRight(numChunksComplete));
//draw incomplete chunks
Console.BackgroundColor = ConsoleColor.Gray;
Console.Write("".PadRight(totalChunks - numChunksComplete));
//draw totals
Console.CursorLeft = totalChunks + 5;
Console.BackgroundColor = ConsoleColor.Black;
string output = progress.ToString() + " of " + total.ToString();
Console.Write(output.PadRight(15) + stepDescription); //pad the output so when changing from 3 to 4 digits we avoid text shifting
}
試してみてください https://www.nuget.org/packages/ShellProgressBar/
私はこのプログレスバーの実装を偶然見つけました-そのクロスプラットフォーム、本当に使いやすく、非常に設定可能で、箱から出してすぐにすべきことをします。
私はそれがとても好きだったので、ただ共有しています。
System.Reactiveで動作するこの便利なクラスを作成しました。あなたがそれを十分に素敵に見つけることを願っています。
public class ConsoleDisplayUpdater : IDisposable
{
private readonly IDisposable progressUpdater;
public ConsoleDisplayUpdater(IObservable<double> progress)
{
progressUpdater = progress.Subscribe(DisplayProgress);
}
public int Width { get; set; } = 50;
private void DisplayProgress(double progress)
{
if (double.IsNaN(progress))
{
return;
}
var progressBarLenght = progress * Width;
System.Console.CursorLeft = 0;
System.Console.Write("[");
var bar = new string(Enumerable.Range(1, (int) progressBarLenght).Select(_ => '=').ToArray());
System.Console.Write(bar);
var label = $@"{progress:P0}";
System.Console.CursorLeft = (Width -label.Length) / 2;
System.Console.Write(label);
System.Console.CursorLeft = Width;
System.Console.Write("]");
}
public void Dispose()
{
progressUpdater?.Dispose();
}
}
私はこのスレッドにつまずいて何か他のものを探していましたが、DownloadProgressChangedを使用してファイルのリストをダウンロードするコードをまとめてドロップすると思いました。これは非常に役立つので、進行状況だけでなく、ファイルが通過する実際のサイズも確認できます。それが誰かを助けることを願っています!
public static bool DownloadFile(List<string> files, string Host, string username, string password, string savePath)
{
try
{
//setup FTP client
foreach (string f in files)
{
FILENAME = f.Split('\\').Last();
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
wc.DownloadFileAsync(new Uri(Host + f), savePath + f);
while (wc.IsBusy)
System.Threading.Thread.Sleep(1000);
Console.Write(" COMPLETED!");
Console.WriteLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return false;
}
return true;
}
private static void ProgressChanged(object obj, System.Net.DownloadProgressChangedEventArgs e)
{
Console.Write("\r --> Downloading " + FILENAME +": " + string.Format("{0:n0}", e.BytesReceived / 1000) + " kb");
}
private static void Completed(object obj, AsyncCompletedEventArgs e)
{
}
出力の例を次に示します。
それが誰かを助けることを願っています!