PDA

View Full Version : سوال: کپی فایل



qasemf
دوشنبه 17 شهریور 1399, 00:02 صبح
سلام دوستان یه اپ نوشتم واسه انتقال فایل چند وقت پیش چون فقط میخواستم ببینم انتقال انجام میده یا نه..یه کپی ساده نوشتم اما حالا میخوام زمانی که مثلا یه سری فایل و فولدر رو انتخاب کردم نرم افزار بتونه به درستی کپی کنه اما الگوریتم این کار رو نمیفهمم... الان من مثلا ۲ تا فایل رو همراه با ۲تا پوشه کپی میکنم که هر پوشه خودشون مثلا ۲تا فایل دارن حالا سوال اینجاست چندتا حلقه بزارم و ایا تو در تو باشن؟ من برنامه رو ایتطور نوشتم که فایل هایی رو که انتخاب میکنم همشون کپی میشتن تو کلیپ برد و زمانی که past میزنم ادرس و نام این فایل ها از کلیپ برد خونده میشن حالا مثلا تو لاین اول و دوم یه فایل دارم و لاین سوم یه پوشه دارم که این پوشه دو تا فایل داره حالا استراتژی چیه؟

the king
دوشنبه 17 شهریور 1399, 03:45 صبح
سلام دوستان یه اپ نوشتم واسه انتقال فایل چند وقت پیش چون فقط میخواستم ببینم انتقال انجام میده یا نه..یه کپی ساده نوشتم اما حالا میخوام زمانی که مثلا یه سری فایل و فولدر رو انتخاب کردم نرم افزار بتونه به درستی کپی کنه اما الگوریتم این کار رو نمیفهمم... الان من مثلا ۲ تا فایل رو همراه با ۲تا پوشه کپی میکنم که هر پوشه خودشون مثلا ۲تا فایل دارن حالا سوال اینجاست چندتا حلقه بزارم و ایا تو در تو باشن؟ من برنامه رو ایتطور نوشتم که فایل هایی رو که انتخاب میکنم همشون کپی میشتن تو کلیپ برد و زمانی که past میزنم ادرس و نام این فایل ها از کلیپ برد خونده میشن حالا مثلا تو لاین اول و دوم یه فایل دارم و لاین سوم یه پوشه دارم که این پوشه دو تا فایل داره حالا استراتژی چیه؟
شما ابتدای کار یک لیست ورودی دارید که تعدادی فایل و پوشه داخلش هست که باید از مسیر مبدا به مسیر مقصد کپی بشن. موقع بررسی آیتم های این لیست با File.Exists و Directory.Exists می توانیم تشخیص بدهیم که آیتم فایل ئه یا پوشه. اگر فایل بود که صرفا کپی اش می کنیم ولی اگر پوشه بود علاوه بر اینکه پوشه ای با اون نام در مسیر مقصد ایجاد می کنیم، فایل ها و پوشه های داخلش رو هم به انتهای لیست اضافه می کنیم تا در ادامه اونها هم کپی بشن.
برای اینکار نیازی به متد بازگشتی نیست، حلقه تو در تو هم مناسب نیست چون نمیدانیم با چند تا زیر پوشه داخل هم مواجه می شویم.
فرض کنیم که می خواهیم این سه تا آیتم رو از مسیری به مسیر دیگری کپی کنیم و هر پوشه خودش حاوی زیر پوشه ها و فایل هایی است.
152140
و داخل Clipboard قرار گرفته اند :

Clipboard.Clear();
Clipboard.SetText ("Folder1|Folder2|Text3.txt". Replace("|", Environment.NewLine));


و می خواهیم از مسیر D:\Source کپی شان کنیم در مسیر E:\Dest، یعنی :
D:\Source\Folder1 و محتویاتش را کپی کنیم در E:\Dest\Folder1
D:\Source\Folder2 و محتویاتش را کپی کنیم در E:\Dest\Folder2
D:\Source\Text3.txt را کپی کنیم در E:\Dest\Text3.txt


var source = @"D:\Source";
var dest = @"E:\Dest";
var items = Clipboard.GetText().Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
CopyFiles(source, dest, items);



private static void CopyFiles(string source, string dest, string[] items)
{
source = Path.GetFullPath(source);
dest = Path.GetFullPath(dest);
var list = new List<string>(items);
for (var i = 0; i < list.Count; i++)
{
var sourcePath = Path.Combine(source, list[i]);
if (Directory.Exists(sourcePath))
{
var destFolder = Path.Combine(dest, list[i]);
if (Directory.Exists(destFolder) == false)
{
Directory.CreateDirectory(destFolder);
}
foreach (var file in Directory.GetFiles(sourcePath))
{
list.Add( file.Substring(source.Length).TrimStart ('\\', '/'));
}
foreach (var folder in Directory.GetDirectories(sourcePath))
{
list.Add( folder.Substring(source.Length).TrimStart ('\\', '/'));
}
}
else if (File.Exists(sourcePath))
{
var destFile = Path.Combine(dest, list[i]);
File.Copy(sourcePath, destFile, true);
}
}
}

qasemf
دوشنبه 17 شهریور 1399, 22:15 عصر
ممنون فقط مهندس فرق settext با setfiledroplist چیه؟ چون من قبلا از setfiledroplistاستفاده کردم الان که میخوام لیست فایل هایی که انتخاب کردم رو تو clipboard ذخیره کنم نمیشه .. دقیقا مثل خود ویندوز که چنتا فایل رو انتخاب میکنیم و کپی میزنیم...اینجام میخوام همین اتفاق بیافته حالا الان فایل هایی که انتخاب میکنم اول میریختم داخلstringcollection و با setfiledroplist کپی میکردم تو clipboard اما حالا settextرو که میزنم فقط یک فایل میره تو clipboard

the king
دوشنبه 17 شهریور 1399, 23:43 عصر
ممنون فقط مهندس فرق settext با setfiledroplist چیه؟ چون من قبلا از setfiledroplistاستفاده کردم الان که میخوام لیست فایل هایی که انتخاب کردم رو تو clipboard ذخیره کنم نمیشه .. دقیقا مثل خود ویندوز که چنتا فایل رو انتخاب میکنیم و کپی میزنیم...اینجام میخوام همین اتفاق بیافته حالا الان فایل هایی که انتخاب میکنم اول میریختم داخلstringcollection و با setfiledroplist کپی میکردم تو clipboard اما حالا settextرو که میزنم فقط یک فایل میره تو clipboard
Clipboard تا 256 فرمت متفاوت داده رو میتونه در خودش نگه داره، SetText و SetFileDropList برای قرار دادن مقدار با دو فرمت متفاوت هستند.
من صرفا یک مثال برای پر کردن Clipboard زدم، اطلاعی از فرمت مورد استفاده شما نداشتم.
برای فرمت FileDropList از همون Clipboard.SetFileDropList استفاده کنید، البته مسیر فایل و پوشه ها رو باید کامل بدهید، چون دیگه مسیر مبدا source ای وجود نداره.

private static void CopyFileDropList(string dest)
{
dest = Path.GetFullPath(dest);
var list = new List<KeyValuePair<string, string>>();
foreach (var item in Clipboard.GetFileDropList())
{
list.Add(new KeyValuePair<string, string>(item, dest));
}
for (var i = 0; i < list.Count; i++)
{
if (Directory.Exists(list[i].Key))
{
var destFolder = Path.Combine(list[i].Value, Path.GetFileName(list[i].Key));
if (Directory.Exists(destFolder) == false)
{
Directory.CreateDirectory(destFolder);
}
foreach (var file in Directory.GetFiles(list[i].Key))
{
list.Add(new KeyValuePair<string, string>(file, destFolder));
}
foreach (var folder in Directory.GetDirectories(list[i].Key))
{
list.Add(new KeyValuePair<string, string>(folder, destFolder));
}
}
else if (File.Exists(list[i].Key))
{
var destFile = Path.Combine(list[i].Value, Path.GetFileName(list[i].Key));
File.Copy(list[i].Key, destFile, true);
}
}
}



var dest = @"E:\Dest";
CopyFileDropList(dest);

qasemf
چهارشنبه 19 شهریور 1399, 01:42 صبح
Clipboard تا 256 فرمت متفاوت داده رو میتونه در خودش نگه داره، SetText و SetFileDropList برای قرار دادن مقدار با دو فرمت متفاوت هستند.
من صرفا یک مثال برای پر کردن Clipboard زدم، اطلاعی از فرمت مورد استفاده شما نداشتم.
برای فرمت FileDropList از همون Clipboard.SetFileDropList استفاده کنید، البته مسیر فایل و پوشه ها رو باید کامل بدهید، چون دیگه مسیر مبدا source ای وجود نداره.

private static void CopyFileDropList(string dest)
{
dest = Path.GetFullPath(dest);
var list = new List<KeyValuePair<string, string>>();
foreach (var item in Clipboard.GetFileDropList())
{
list.Add(new KeyValuePair<string, string>(item, dest));
}
for (var i = 0; i < list.Count; i++)
{
if (Directory.Exists(list[i].Key))
{
var destFolder = Path.Combine(list[i].Value, Path.GetFileName(list[i].Key));
if (Directory.Exists(destFolder) == false)
{
Directory.CreateDirectory(destFolder);
}
foreach (var file in Directory.GetFiles(list[i].Key))
{
list.Add(new KeyValuePair<string, string>(file, destFolder));
}
foreach (var folder in Directory.GetDirectories(list[i].Key))
{
list.Add(new KeyValuePair<string, string>(folder, destFolder));
}
}
else if (File.Exists(list[i].Key))
{
var destFile = Path.Combine(list[i].Value, Path.GetFileName(list[i].Key));
File.Copy(list[i].Key, destFile, true);
}
}
}



var dest = @"E:\Dest";
CopyFileDropList(dest);



نمیشه کاری کرد که هر چقدر زیر پوشه وجود داشت رو بتونه کپی کنه؟ چون اینطوری فقط فایلها و پوشه های یک زیر پوشه رو برمیگردونه یعنی اگه پوشه ها حداقل 3 بار داخل هم رفته باشن فقط میره داخل پوشه اول و هرچی پوشه داشت و فایل داخل این پوشه ها بود رو کپی میکنه ..اگه داخل پوشه دوم ، یه پوشه باشه و باز داخل پوشه سوم فایل باشه دیگه عمل نمیکنه...
همون روش تو در تو باید جواب بده فک کنم
ینی میتونیم اینطوری بگیم وقتی لیست فایل ها رو از کلیپ برد دریافت کرده به عنوان مثال خونه اول لیست یه دایرکتوری هست ، بره داخلش و تا زمانی که تمام فایلها و زیرپوشه های این دایرکتوری رو کپی نکرده بیرون نیاد و بعد بیاد بره خونه دوم لیست رو چک کنه و الی اخر اینطوری نمیشه؟

the king
چهارشنبه 19 شهریور 1399, 05:58 صبح
نمیشه کاری کرد که هر چقدر زیر پوشه وجود داشت رو بتونه کپی کنه؟ چون اینطوری فقط فایلها و پوشه های یک زیر پوشه رو برمیگردونه یعنی اگه پوشه ها حداقل 3 بار داخل هم رفته باشن فقط میره داخل پوشه اول و هرچی پوشه داشت و فایل داخل این پوشه ها بود رو کپی میکنه ..اگه داخل پوشه دوم ، یه پوشه باشه و باز داخل پوشه سوم فایل باشه دیگه عمل نمیکنه...
همون روش تو در تو باید جواب بده فک کنم
ینی میتونیم اینطوری بگیم وقتی لیست فایل ها رو از کلیپ برد دریافت کرده به عنوان مثال خونه اول لیست یه دایرکتوری هست ، بره داخلش و تا زمانی که تمام فایلها و زیرپوشه های این دایرکتوری رو کپی نکرده بیرون نیاد و بعد بیاد بره خونه دوم لیست رو چک کنه و الی اخر اینطوری نمیشه؟
همینطوری حدس نزنید که عمل می کنه یا نمی کنه، یا کد رو در اجرا بررسی کنید یا سطر به سطر تحلیلش کنید.
اون سطر foreach (var folder in Directory.GetDirectories رو در کد می بینید؟ هر زیر پوشه ای پیدا کنه به آخر لیست اضافه می کنه تا بعدا بررسی بشه.
باز اگر موقع بررسی اون پوشه زیر پوشه ای داشته باشه باز به آخر لیست اضافه میشه و ...
حتی اگه بیست مرحله پوشه در پوشه هم باشه کل ساحتارش کپی میشه، چیزی از قلم نمی افته.

qasemf
چهارشنبه 19 شهریور 1399, 23:44 عصر
یه اشتباهی انجام داده بودم واسه همین درست عمل نمیکرد الان درست داره کار میکنه اما درکش سخته چطوری داره کار میکنه چون زیاد با حلقه forech کار نکردم واسه همین یکم درکش سخته اما حتما تحلیلش میکنم( البته از زیر پوشه دو و سوم به بعد نمیفهم)
فقط مهندس چیزی که برام جالبه اینکه نمدونم چرا progressbar دیگه عمل کپی شدن رو نشون نمیده تو اون یکی پست بهم گفتین که ازopenread استفاده کنم الانم هیچ مشکلی نیست فرایند انتقال بدون هیچ خطایی اتفاق می افته اما progressbar کماکان زمان انتقال بدون تغییر باقی میمونه خیلی برام جالبه!!! به نظر شما مشکل کجا میتونه باشه؟ همه متدها رو چک کردم بدون تغییر بودن تغییری تو متدها انجام ندادم ولی...اینم سورس کامل

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

namespace WindowsFormsApp1
{
public partial class Transfer_form : Form
{

System.Collections.Specialized.StringCollection replacementList = new System.Collections.Specialized.StringCollection();
List<string> myList = new List<string>();
BackgroundWorker worker = new BackgroundWorker();
public string form_path = "";
private bool button1WasClicked = false;
public Transfer_form()
{
InitializeComponent();
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;
worker.DoWork += Worker_DoWork;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;

worker.ProgressChanged += Worker_ProgressChanged;
//
}


private void Transfer_form_Load(object sender, EventArgs e)
{
textBox1.Text =form_path;

replacementList=(Clipboard.GetFileDropList());


for (int i = 0; i < replacementList.Count; i++)
{
listfiles.Items.Add(replacementList[i].ToString());
}
this.listfiles.View = System.Windows.Forms.View.List;

}

private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
if (Directory.Exists(textBox1.Text+"/"+"HiradMedia") == false)
{
Directory.CreateDirectory(textBox1.Text + "/" + "HiradMedia");

}
var dest = Path.GetFullPath(textBox1.Text + "/" + "HiradMedia");
var list = new List<KeyValuePair<string, string>>();
foreach (var item in Clipboard.GetFileDropList())
{
list.Add(new KeyValuePair<string, string>(item, dest));
}
for (var i = 0; i < list.Count; i++)
{
if (Directory.Exists(list[i].Key))
{
var destFolder = Path.Combine(list[i].Value, Path.GetFileName(list[i].Key));
if (Directory.Exists(destFolder) == false)
{
Directory.CreateDirectory(destFolder);
}
foreach (var file in Directory.GetFiles(list[i].Key))
{
list.Add(new KeyValuePair<string, string>(file, destFolder));
}
foreach (var folder in Directory.GetDirectories(list[i].Key))
{
list.Add(new KeyValuePair<string, string>(folder, destFolder));
}
}
else if (File.Exists(list[i].Key))
{
var destFile = Path.Combine(list[i].Value, Path.GetFileName(list[i].Key));
File.Copy(list[i].Key, destFile);
}
}
}
private void Copy(string source, string destination)
{

FileStream fsout = new FileStream(destination, FileMode.Create);
using (var fsin = File.OpenRead(source))
{
byte[] buffer = new byte[1048756];//1 mb
int readbyte;
while ((readbyte = fsin.Read(buffer, 0, buffer.Length)) > 0)
{
fsout.Write(buffer, 0, readbyte);
worker.ReportProgress((int)(fsin.Position * 100 / fsin.Length));
if (worker.CancellationPending)
{
// e.Cancel = true;
worker.ReportProgress(0);
fsin.Close();
fsout.Close();
return;
}
}
}


}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{

if (e.Cancelled)
{
progressBar1.Visible = false;
MessageBox.Show("operation is abort", "abort", MessageBoxButtons.OK, MessageBoxIcon.Information);

}
else {

progressBar1.Visible = true;
MessageBox.Show("operation is completed", "abort", MessageBoxButtons.OK, MessageBoxIcon.Information);

}
}
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}

private void btncopy_Click(object sender, EventArgs e)
{
// worker.RunWorkerAsync();
button1WasClicked = true;
if(button1WasClicked)
{
worker.RunWorkerAsync();
btncopy.Enabled = false;
}


}
public void passList(List<string> mList)
{

}

}
}

the king
پنج شنبه 20 شهریور 1399, 05:27 صبح
یه اشتباهی انجام داده بودم واسه همین درست عمل نمیکرد الان درست داره کار میکنه اما درکش سخته چطوری داره کار میکنه چون زیاد با حلقه forech کار نکردم واسه همین یکم درکش سخته اما حتما تحلیلش میکنم( البته از زیر پوشه دو و سوم به بعد نمیفهم)
فقط مهندس چیزی که برام جالبه اینکه نمدونم چرا progressbar دیگه عمل کپی شدن رو نشون نمیده تو اون یکی پست بهم گفتین که ازopenread استفاده کنم الانم هیچ مشکلی نیست فرایند انتقال بدون هیچ خطایی اتفاق می افته اما progressbar کماکان زمان انتقال بدون تغییر باقی میمونه خیلی برام جالبه!!! به نظر شما مشکل کجا میتونه باشه؟ همه متدها رو چک کردم بدون تغییر بودن تغییری تو متدها انجام ندادم ولی...اینم سورس کامل

دو تا مساله هست، اول اینکه متد void Copy رو دارید ولی برای کپی کردن فایلها بجای این متد از File.Copy استفاده میشه. برای همین دلیل متد Copy تون تاثیر نداره.
مساله دوم اینه که قبل از شروع به عملیات کپی، حجم مجموعه فایل ها محاسبه نشده، معلوم نیست حجم این فایلی که داره کپی میشه چند درصد از حجم کل مجموعه است.
برای همین ProgressBar صرفا بر اساس حجم اون فایلی که الان داره کپی میشه اطلاعات میده، فایل بعدی رو که بخواد کپی کنه باز برمیگرده به موقعیت 0.
با این ProgressBar که صرفا پیشرفت کپی شدن یک فایل رو مشخص می کنه، معلوم نمیشه که در کپی کردن همه فایلها چقدر پیشرفت حاصل شده.
اصولا باید پیش از شروع عملیات کپی ابتدا با FileInfo.Length (https://docs.microsoft.com/en-us/dotnet/api/system.io.fileinfo.length?view=netcore-3.1) حجم فایل ها بدست بیاد، با هم جمع زده بشه تا مشخص کنیم قراره در مجموع چه حجمی از داده رو کپی کنیم.
اینطوری موقع کپی کردن فایل ها می توانیم ProgressBar رو برحسب پیشرفت کل عملیات کپی جلو ببریم، نه فقط یک فایل.

qasemf
جمعه 21 شهریور 1399, 02:32 صبح
سپاس فراوان
مهندس واقعا ممنونم ببخشید اگه باعث اذیت شدم چون زیاد وارد نیستم تو کدنویسی