PDA

View Full Version : دانلودری نوشتم که فایل رو ناقص دانلود میکنه، متد بهینه چی هست براش؟ + عکس



vahid-p
سه شنبه 05 شهریور 1392, 17:32 عصر
سلام دوستان
یه دانلودر ساده نوشتم که کار میکنه ولی آخر سر میبینی فایل ناقص دانلود شده!

اول این عکس رو ببینید :
109790

خب تو این عکس لینک و محل ذخیره رو مشخص میکنیم. رو لینکی دومی مثلا کلیک میکنم و start میزنم سریع دانلود میشه و 100 درصد که شد، آخرش میبینی فایل ناقص دانلود شده. حتی فایل zip، یعنی لینک اولی، نوشته 554 کیلوبایت ولی وقتی دانلود میکنه میبینی 600 و خورده ای شده و فایل ناقصه.
خلاصه چندین بار که امتحان کردم همین مشکل رو داره. مطمئنا ایراد از کدش هست.

اینم کد قسمت دانلودش :
new Thread(new Runnable() {

@Override
public void run() {
FileOutputStream fout = null;
InputStream input = null;
try {
long fileSize;
URL url=new URL((String)(jTable2.getValueAt(jTable2.getSelecte dRow(), 4)));
URLConnection connection;
connection = url.openConnection();
connection.connect();
fileSize=connection.getContentLength();
input=new BufferedInputStream(connection.getInputStream());
fout=new FileOutputStream(new File(filelocationAddress));

byte[] data=new byte[1024];
long downloaded=0;
int byteDownloadedinThisCycle=0;
while((byteDownloadedinThisCycle=input.read(data)) !=-1){
fout.write(data);
downloaded+=byteDownloadedinThisCycle;
jTable2.setValueAt("%"+(downloaded*100)/fileSize, jTable2.getSelectedRow(), 1);
}
fout.flush();
} catch (IOException ex) {
Logger.getLogger(MainPage.class.getName()).log(Lev el.SEVERE, null, ex);
}finally{
try {
fout.close();
input.close();
} catch (IOException ex) {
Logger.getLogger(MainPage.class.getName()).log(Lev el.SEVERE, null, ex);
}
}
}
}).start();

vahid-p
چهارشنبه 06 شهریور 1392, 16:12 عصر
کسی نبود راهنمایی کنه؟

vahid-p
چهارشنبه 27 شهریور 1392, 19:10 عصر
اینجا که کسی نیست راهنمایی کنه مجبورم خودم آخرش یه جوری حلش کنم.
این مشکل به راحتی حل شد، ولی یه مشکل دیگه از نظر بهینه سازی داره که البته خیلی هم مهمه.
خب مشکل به چه صورتی حل شد.

من به جایی که یک آرایه بگیرم و هر بار آرایه ای از بایت ها رو ذخیره کنم، میام و یک بایت یک بایت میگیرم. اینجوری خونه های خالی آرایه به فایل راه پیدا نمیکنن و فایل خراب نمیشه و دقیق کار میکنه.
در کد بالا به جای خط 17 تا 24 اینا رو مینویسیم :
long downloaded=0;
int reader;
while((reader=input.read())!=-1){
fout.write(reader);
downloaded+=1;
jTable2.setValueAt("%"+(downloaded*100)/fileSize, jTable2.getSelectedRow(), 1);
}

خب این برای هر فایلی به راحتی اجرا میشه و هیچ مشکلیی نداره، ولی مشکل اصلی اینه چون یه بایت یه بایت میگیره، اگر سرعت اینترنت 70 کیلوبایت بر ثانیه باشه در هر ثانیه این حلقه 70000 بار اجرا میشه. حالا اگر سرعت 1 مگابایت باشه که 1 میلیون بار در هر ثانیه اجرا میشه. من با سرعت 70 کیلوبایت CPU حدود 40 درصد برای این برنامه ساده مصرف میکنه.
برای همینه هم بهتر بود به صورت آرایه ای ذخیره بشه، که اونم مشکلش رو گفتم که فایل رو خراب میکنه.

من دو راه به ذهنم میاد :
اول مثلا 1000 بایت 1000 بایت تو یه آرایه ذخیره کنم و بعد ادامش. یا هم اینکه همون روشی که تو پست قبل هست ولی برای آخرای دانلود یا بهترش اینکه هر بار چک کنه اگه طول بایت ها دانلود شده کمتر از 1024 بود و بیاد دونه دونه ذخیره کنه چون تو آزمایش زیر میبینید دفعات زیادی هست که کل آرایه همراه هم دانلود نمیشه ( که اول فکر میکردم فقط آخرین آرایه اینطوره و این نکته جالبی بود )، بیاد و دقیقا چک کنه چقدر از آرایه پر شده و دقیقا اونقدر از آرایه رو به فایل منتقل کنه.
اینم کدش (که دقیق کار میکنه و از نظر مصرف سی پی یو خیلی پایینه ) :
byte[] data=new byte[1024];
int byteDownloadedinThisCycle=0;
while((byteDownloadedinThisCycle=input.read(data)) !=-1){
if(byteDownloadedinThisCycle<1024){
System.out.println(byteDownloadedinThisCycle);
for(int j=0;j<byteDownloadedinThisCycle;j++){
fout.write(data[j]);
}
}else{
fout.write(data);
}
downloaded+=byteDownloadedinThisCycle;
jTable2.setValueAt("%"+(downloaded*100f)/fileSize, jTable2.getSelectedRow(), 1);
}
اون System.out.println در داخل حلقه برای اینه که ببینیم چند بار آرایه 1024 بایتی کامل دانلود نمیشه و با این حال وارد فایل میشه ( که در پست اول باعث خرابی فایل می شد )
این روش درستیه یا روش بهتری هم دارید براش؟ ( فکر کنم آخرش هیچکی جواب نده و به همین روش من در آوردی خودم اکتفا کنم :) )