Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm programming a multiple file downloader in Java with JavaFx, but i have some problems with threading.
The problem i have is with the threading part.
I want to start multiple downloads (different urls / files) at the same time, for example two. If i start this two downloadthreads (I think) a race condition happens, because the filename and filesize for both threads are the same and there is also only one file on the HDD, not two as expected.
I am sure it's a race condition problem, but how can i solve it?
Main.java
package de.minimal.program;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import de.minimal.program.model.Download;
import de.minimal.program.util.Dl;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
public class Main extends Application {
private ObservableList<Download> downloadData = FXCollections.observableArrayList();
private int i = 0;
public ObservableList<Download> getDownloadData(){
return downloadData;
}
#Override
public void start(Stage primaryStage) {
downloadData.add(new Download("http://mirror.de.leaseweb.net/videolan/vlc/2.2.1/win32/vlc-2.2.1-win32.exe"));
downloadData.add(new Download("http://releases.ubuntu.com/15.10/ubuntu-15.10-desktop-amd64.iso"));
ArrayList<Thread> t = new ArrayList<Thread>();
ExecutorService executor = Executors.newFixedThreadPool(2, new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread a = new Thread(r);
a.setName("Thread " + i);
i++;
t.add(a);
return a;
}
});
for(Download dl : downloadData){
Dl d = new Dl(dl);
executor.execute(d);
}
}
public static void main(String[] args) {
launch(args);
}
}
DL.java
package de.minimal.program.util;
import java.util.List;
import de.minimal.program.httpconnection.HttpConnection;
import de.minimal.program.model.Download;
import javafx.concurrent.Task;
public class Dl extends Task<List<Download>> implements Runnable{
private Download download;
private HttpConnection connection;
public Dl(Download download){
this.download = download;
}
#Override
protected synchronized List<Download> call() throws Exception {
connection = new HttpConnection(download);
connection.downloadFile();
return null;
}
}
HTTPConnection.java
package de.minimal.program.httpconnection;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import de.minimal.program.model.Download;
public class HttpConnection {
private static String url;
private Download download;
private static final int BUFFER_SIZE = 4096;
public HttpConnection(Download download){
this.download = download;
}
public void downloadFile() throws IOException{
String saveDir = download.getDownloadSavePath();
url = download.getDownloadUrl();
URL obj = new URL(url);
HttpURLConnection connection = (HttpURLConnection) obj.openConnection();
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
// Forbid redirects for file resuming reasons
connection.setInstanceFollowRedirects(false);
int responseCode = connection.getResponseCode();
// always check HTTP response code first
if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_PARTIAL) {
String fileName = "";
String disposition = connection.getHeaderField("Content-Disposition");
long contentLength = connection.getContentLengthLong();
boolean appendToFile = false;
if(responseCode == HttpURLConnection.HTTP_PARTIAL)
appendToFile = true;
if(download.getFilesize() == 0){
download.setFilesize(contentLength);
}
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename=");
if (index > 0) {
fileName = disposition.substring(index + 10,
disposition.length() - 1);
}
} else {
// extracts file name from URL
fileName = url.substring(url.lastIndexOf("/") + 1, url.length());
}
download.setFilename(fileName);
// opens input stream from the HTTP connection
InputStream inputStream = connection.getInputStream();
String saveFilePath = saveDir + File.separator + fileName;
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath, appendToFile);
int bytesRead = -1;
long downloadedBytes = download.getTransferedBytes();
long start = System.currentTimeMillis();
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
downloadedBytes += bytesRead;
if(System.currentTimeMillis() - start >= 2000){
download.setTransferedBytes(downloadedBytes);
start = System.currentTimeMillis();
}
}
outputStream.close();
inputStream.close();
System.out.println("Thread " + Thread.currentThread().getName() + " Filedownload " + fileName + " finished");
} else {
System.out.println("No file to download. Server replied HTTP code: " + responseCode);
}
connection.disconnect();
}
}
Download.java
package de.minimal.program.model;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Download {
private final StringProperty filename;
private final StringProperty filepath;
private final LongProperty filesize;
private final LongProperty transferedBytes;
private String downloadUrl;
private String downloadSavePath = "SET PATH ";
public Download(){
this("");
}
public Download(String downloadUrl){
this.downloadUrl = downloadUrl;
this.filename = new SimpleStringProperty(downloadUrl);
this.filepath = new SimpleStringProperty(downloadSavePath);
this.filesize = new SimpleLongProperty(0);
this.transferedBytes = new SimpleLongProperty(0);
}
// Filename
public synchronized String getFilename(){
return filename.get();
}
public synchronized void setFilename(String filename){
System.out.println("Thread " + Thread.currentThread().getName() + " Set filename: " + filename);
this.filename.set(filename);
}
public synchronized StringProperty filenameProperty(){
return filename;
}
// Filepath
public String getFilepath(){
return filepath.get();
}
public void setFilepath(String filepath){
System.out.println("Set filepath: " + filepath);
this.filepath.set(filepath);
}
public StringProperty filepathProperty(){
return filepath;
}
// Filesize
public Long getFilesize(){
return filesize.get();
}
public void setFilesize(Long filesize){
System.out.println("Thread " + Thread.currentThread().getName() + " Set filesize: " + filesize);
this.filesize.set(filesize);
}
public LongProperty filesizeProperty(){
return filesize;
}
// TransferedBytes
public Long getTransferedBytes(){
return transferedBytes.get();
}
public void setTransferedBytes(Long transferedBytes){
System.out.println("Thread " + Thread.currentThread().getName() + " bytes transfered " + transferedBytes);
this.transferedBytes.set(transferedBytes);
}
public LongProperty transferedBytesProperty(){
return transferedBytes;
}
// URL
public String getDownloadUrl(){
return downloadUrl;
}
public void setDownloadUrl(String downloadUrl){
this.downloadUrl = downloadUrl;
}
// SavePath
public String getDownloadSavePath(){
return downloadSavePath;
}
public void setDownloadSavePath(String downloadSavePath){
this.downloadSavePath = downloadSavePath;
}
}
EDIT:
This is the minimal code.
You can add links, start and stop downloads, and change the number of simultaneous concurrent downloads.
EDIT 2:
Minified it again. Hope this time its better.
Adds two downloadlinks and starts them immediately. Reproduces the mentioned problem.
EDIT 3:
Solved it.
The problem was the
private static String url;
I remember that my professor told once that static variables are not thread safe. So more information can found here
10 points about Static in Java point 2
Is writing in a single file a real constraint ? What you could do is to write in separate files, then once the files are complete, merge them into a single one.
Alternatively, if the results from the requests are not so big and could fit in memory, you could directly return the files from the downloading threads, and then write them into a single file.
Related
I'm working on a springboot backend server to provide an audio interface to the android frontend. I expose the audio directory to the outside world directly in the application.yaml file. But in this way, I found that the audio playback has a delay of about 5s before it can be played when I use docker to deploy the .jar to the cloud server. But when I went to test the network interface of some music web, I found that they were very fast and could start playing almost instantly. I wonder how this is done? Can this be achieved if springboot is used as the backend?
this is a part of application.yaml, where web.sound-path is the folder path where I store the audio on cloud server.
spring:
web:
resources:
static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${web.sound-path}
The android frontend directly accesses http://ip:port/audioname.mp3 to play audio.
I am a novice in the development of java network, I do not know how to further improve, I hope someone can give detailed other solutions
my springboot version is 2.7.5
And my cloud server has 10Mbps bandwidth, quad-core CPU and 8G memory.
I've looked for a lot of information online but nothing is of much help, I'd really appreciate if someone could give a good answer.
I've tried two other methods on the web.
One is to use a NonStaticResourceHttpRequestHandler.
the NonStaticResourceHttpRequestHandler is :
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import javax.servlet.http.HttpServletRequest;
import java.nio.file.Path;
#Component
public class NonStaticResourceHttpRequestHandler extends ResourceHttpRequestHandler {
public final static String ATTR_FILE = "NON-STATIC-FILE";
#Override
protected Resource getResource(HttpServletRequest request) {
final Path filePath = (Path) request.getAttribute(ATTR_FILE);
return new FileSystemResource(filePath);
}
}
and the method in controller is :
#GetMapping("/get/{name}")
public void getSound(#ApiParam("name") #PathVariable("name") String name, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
Path path = Paths.get(soundPath + name);
if (Files.exists(path)) {
String mimeType = Files.probeContentType(path);
if (!StringUtils.isEmpty(mimeType)) {
response.setContentType(mimeType);
}
request.setAttribute(NonStaticResourceHttpRequestHandler.ATTR_FILE, path);
nonStaticResourceHttpRequestHandler.handleRequest(request, response);
} else {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
}
}
another solution I have tried is: (The code in it may not be very beautiful, because I rewritten it based on the existing code on the Internet.)
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
#RestController
#RequestMapping("/audio")
public class AudioVideoController {
#Value("${web.sound-path}")
public String AUDIO_PATH;
public static final int BYTE_RANGE = 128; // increase the byterange from here
#GetMapping("/play/{fileName}")
public ResponseEntity<byte[]> streamAudio(#RequestHeader(value = "Range", required = false) String httpRangeList,
#PathVariable("fileName") String fileName) {
return getContent(AUDIO_PATH, fileName, httpRangeList, "audio");
}
private ResponseEntity<byte[]> getContent(String location, String fileName, String range, String contentTypePrefix) {
long rangeStart = 0;
long rangeEnd;
byte[] data;
Long fileSize;
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
try {
fileSize = Optional.ofNullable(fileName)
.map(file -> Paths.get(getFilePath(location), file))
.map(this::sizeFromFile)
.orElse(0L);
if (range == null) {
return ResponseEntity.status(HttpStatus.OK)
.header("Content-Type", contentTypePrefix + "/" + fileType)
.header("Content-Length", String.valueOf(fileSize))
.body(readByteRange(location, fileName, rangeStart, fileSize - 1));
}
String[] ranges = range.split("-");
rangeStart = Long.parseLong(ranges[0].substring(6));
if (ranges.length > 1) {
rangeEnd = Long.parseLong(ranges[1]);
} else {
rangeEnd = fileSize - 1;
}
if (fileSize < rangeEnd) {
rangeEnd = fileSize - 1;
}
data = readByteRange(location, fileName, rangeStart, rangeEnd);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
String contentLength = String.valueOf((rangeEnd - rangeStart) + 1);
return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
.header("Content-Type", contentTypePrefix +
"/" + fileType)
.header("Accept-Ranges", "bytes")
.header("Content-Length", contentLength)
.header("Content-Range", "bytes" + " " + rangeStart + "-" + rangeEnd + "/" + fileSize)
.body(data);
}
public byte[] readByteRange(String location, String filename, long start, long end) throws IOException {
Path path = Paths.get(getFilePath(location), filename);
try (InputStream inputStream = (Files.newInputStream(path));
ByteArrayOutputStream bufferedOutputStream = new ByteArrayOutputStream()) {
byte[] data = new byte[BYTE_RANGE];
int nRead;
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
bufferedOutputStream.write(data, 0, nRead);
}
bufferedOutputStream.flush();
byte[] result = new byte[(int) (end - start) + 1];
System.arraycopy(bufferedOutputStream.toByteArray(), (int) start, result, 0, result.length);
return result;
}
}
private String getFilePath(String location) {
return location;
}
private Long sizeFromFile(Path path) {
try {
return Files.size(path);
} catch (IOException ex) {
ex.printStackTrace();
}
return 0L;
}
}
I have tried these two methods, and the audio can be obtained normally, but there is still a delay of a few seconds from the time the http request is sent to the audio starts playing.
I was hoping there was a way to get audio files quickly. The ideal situation is to enter an http request, press the Enter key, and then immediately start playing audio.
I am creating a Web App in which, I have to upload files by splitting them using parallel processing and multi threading and while downloading I have to combine them back to a single file using multi threading and parallel processing.
I want to combine split files into a single. But its not working as I expected to work.
The number of threads created is equal to the number of parts the file have been split.
And the threads should run parallelly and should run only once. But the threads are called several times. Help me fix the code.
UploadServlet.java
import java.util.Arrays;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import org.apache.commons.io.IOUtils;
import jakarta.servlet.*;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import jakarta.servlet.http.HttpServletRequest;
import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class UploadServlet extends HttpServlet
{
private static final long serialVersionUID = 100L;
public static String fileName;
public static long size;
public static int noOfParts;
public static String type;
public static byte[] b;
private static final String INSERT_USERS_SQL = "INSERT INTO uploadlist" +
" (filename, filesize, noofparts) VALUES " +
"(?, ?, ?);";
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Part file = request.getPart("file");
fileName=file.getSubmittedFileName();
type=file.getContentType();
PrintWriter writer=response.getWriter();
file.write(fileName);
String n = request.getParameter("parts");
size = file.getSize();
Integer temp1 = Integer.parseInt(n);
noOfParts = temp1.intValue();
set();
writer.println("File Uploaded Successfully");
file.delete();
}
public static void set()
{
Split.split(fileName,size,noOfParts);
try {
Connection c = DataBaseConnection.getConnection();
PreparedStatement preparedStatement = c.prepareStatement(INSERT_USERS_SQL);
preparedStatement.setString(1, fileName);
preparedStatement.setLong(2, size);
preparedStatement.setInt(3, noOfParts);
System.out.println(preparedStatement);
preparedStatement.executeUpdate();
} catch (Exception e)
{
e.printStackTrace();
}
}
}
From UploadServlet Split.split() is called to split the files into number of parts.
Split.java
import java.io.*;
import java.util.Arrays;
public class Split implements Runnable
{
int i;
long size;
int noOfParts;
String fileName;
Split()
{
fileName="";
}
Split(String fileName, int i, long size, int noOfParts)
{
this.fileName=fileName;
this.i=i;
this.size=size;
this.noOfParts=noOfParts;
}
public void run()
{
try
{
System.out.println(i);
RandomAccessFile in = new RandomAccessFile("D:\\temp\\"+fileName,"r");
int bytesPerSplit = (int)(size/noOfParts);
int remainingBytes = (int)(size % noOfParts);
byte[] b;
if(i!=noOfParts-1)
{
b = new byte[bytesPerSplit];
}
else
{
b = new byte[bytesPerSplit+remainingBytes];
}
in.seek((long)i*bytesPerSplit);
in.read(b);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("D:\\Upload\\"+fileName+i+".bin"));
for(byte temp : b)
out.write(temp);
out.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
public static void split(String fileName, long size, int noOfParts)
{
for(int i=0; i<noOfParts; i++)
{
Split obj = new Split(fileName,i,size,noOfParts);
Thread t = new Thread(obj);
t.start();
}
}
}
In this program, I split the files according to number of parts. And I want to combine them back using Parallel Processing and Multi Threading.
DownloadServlet.java\
import jakarta.servlet.http.HttpServlet;
import org.postgresql.Driver;
import java.sql.Statement;
import java.io.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.DriverManager;
import java.util.Arrays;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class DownloadServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String name = new String(request.getParameter("fileName"));
int noOfParts = Integer.parseInt(request.getParameter("parts"));
int size = Integer.parseInt(request.getParameter("size"));
File downloadFile = new File("D:\\Download\\"+name);
Combine.combine(name,noOfParts,size);
int length = (int)downloadFile.length();
String completeFile=name;
ServletContext context=getServletContext();
String mimeType = context.getMimeType(completeFile);
if (mimeType == null)
{
mimeType = "application/octet-stream";
}
response.setContentType(mimeType);
response.setContentLength((int)length);
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", completeFile);
response.setHeader(headerKey, headerValue);
OutputStream outStream = response.getOutputStream();
DataInputStream in = new DataInputStream(new FileInputStream(downloadFile));
byte[] buffer = new byte[(int)length];
while ((in != null) && ((length = in.read(buffer)) != -1))
{
outStream.write(buffer,0,length);
}
if ((length = in.read(buffer))== -1) {
outStream.write(buffer, 0, length);
}
Arrays.fill(buffer, (byte)0);
in.close();
outStream.flush();
outStream.close();
}
}
From DownloadServlet, Combine.combine() is called to combine the split parts into a single file.
Combine.java
import java.io.*;
import java.util.concurrent.TimeUnit;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.*;
import java.util.Scanner;
import java.util.Arrays;
public class Combine implements Runnable
{
String name;
int size;
int noOfParts;
int i;
public static String root = "D:\\Upload\\";
Combine(String name,int noOfParts,int size, int i)
{
this.name = name;
this.noOfParts=noOfParts;
this.size=size;
this.i=i;
}
public void run()
{
try
{
System.out.println(i);
RandomAccessFile out = new RandomAccessFile("D:\\Download\\"+name,"rw");
int bytesPerSplit = size/noOfParts;
int remainingBytes = size%noOfParts;
String temp=name+i+".bin";
RandomAccessFile file = new RandomAccessFile(root+temp,"r");
long l=file.length();
byte[] b = new byte[(int)l];
file.read(b);
out.seek(i*bytesPerSplit);
out.write(b);
file.close();
out.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
public static void combine(String name, int noOfParts, int size)
{
for(int i=0; i<noOfParts; i++)
{
Combine obj = new Combine(name,noOfParts,size,i);
Thread t = new Thread(obj,"Thread"+i);
t.start();
}
}
}
I have attached the image in which the numbers represent the part of the file being read and combined using threads.
The output shows that the threads keeping on executing again and again.
I don't know where is the error or any logical mistake in my program.
Help me solve this problem.
I'm trying to set up a server on aws with simple http server and save each http post request headers & payload.
It works locally.
My steps after connection via ssh to the ec2 server:
javac Server.java
sudo nohup java Server
It saves the headers to log file but not the payload and it doesn't returns 204 response.
Server.java
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
public class Server {
private static final int PORT = 80;
private static final String FILE_PATH = "/home/ec2-user/logs/";
private static final String UTF8 = "UTF-8";
private static final String DELIMITER = "|||";
private static final String LINE_BREAK = "\n";
private static final String FILE_PREFIX = "dd_MM_YYYY_HH";
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(FILE_PREFIX);
private static final String FILE_TYPE = ".txt";
public static void main(String[] args) {
try {
HttpServer server = HttpServer.create(new InetSocketAddress(PORT), 0);
server.createContext("/", new HttpHandler() {
#Override
public void handle(HttpExchange t) throws IOException {
System.out.println("Req\t" + t.getRemoteAddress());
InputStream initialStream = t.getRequestBody();
byte[] buffer = new byte[initialStream.available()];
initialStream.read(buffer);
File targetFile = new File(FILE_PATH + simpleDateFormat.format(new Date()) + FILE_TYPE);
OutputStream outStream = new FileOutputStream(targetFile, true);
String prefix = LINE_BREAK + t.getRequestHeaders().entrySet().toString() + LINE_BREAK + System.currentTimeMillis() + DELIMITER;
outStream.write(prefix.getBytes());
Map<String, String> queryPairs = new HashMap<>();
String params = new String(buffer);
String[] pairs = params.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
String key = pair.substring(0, idx);
String val = pair.substring(idx + 1);
String decodedKey = URLDecoder.decode(key, UTF8);
String decodeVal = URLDecoder.decode(val, UTF8);
queryPairs.put(decodedKey, decodeVal);
}
outStream.write(queryPairs.toString().getBytes());
t.sendResponseHeaders(204, -1);
t.close();
}
});
server.setExecutor(Executors.newCachedThreadPool());
server.start();
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
e.printStackTrace();
}
}
}
Consider these changes to your handle method. As a starting point, two things are changed:
It reads the complete input and copies that into your file (initialStream.available() might not be the full truth)
catch, log and rethrow IOExceptions (you didn't see your 204 after all)
Consider redirecting your output into files, so you can check what happend on server later:
sudo nohup java Server > server.log 2> server.err &
If you described in more detail the desired target file structure we could figure something out there as well I guess.
#Override
public void handle(HttpExchange t) throws IOException {
try {
System.out.println("Req\t" + t.getRemoteAddress());
InputStream initialStream = t.getRequestBody();
File targetFile = new File(FILE_PATH + simpleDateFormat.format(new Date()) + FILE_TYPE);
OutputStream outStream = new FileOutputStream(targetFile, true);
// This will copy ENTIRE input stream into your target file
IOUtils.copy(initialStream, outStream);
outStream.close();
t.sendResponseHeaders(204, -1);
t.close();
} catch(IOException e) {
e.printStackTrace();
throw e;
}
}
as you have seen before I'm working on a download manager in java, I have asked This Question and I have read This Question But These hadn't solve my problem. now I have wrote another code in java. but there is a problem. when download finishes file is larger than it's size and related software can't read it
This is image of my code execution :
as you see file size is about 9.43 MB
This is My project directory's image:
as you see my downloaded filesize is about 13 MB
So what is my Prooblem?
here is my complete source code
Main Class:
package download.manager;
import java.util.Scanner;
/**
*
* #author Behzad
*/
public class DownloadManager {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter url here : ");
String url = input.nextLine();
DownloadInfo information = new DownloadInfo(url);
}
}
DownloadInfo Class:
package download.manager;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DownloadInfo {
private String downloadUrl;
private String fileName;
private String fileExtension;
private URL nonStringUrl;
private HttpURLConnection connection;
private int fileSize;
private int remainingByte;
private RandomAccessFile outputFile;
public DownloadInfo(String downloadUrl) {
this.downloadUrl = downloadUrl;
initiateInformation();
}
private void initiateInformation(){
fileName = downloadUrl.substring(downloadUrl.lastIndexOf('/') + 1, downloadUrl.length());
fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length());
try {
nonStringUrl = new URL(downloadUrl);
connection = (HttpURLConnection) nonStringUrl.openConnection();
fileSize = ((connection.getContentLength()));
System.out.printf("File Size is : %d \n", fileSize);
System.out.printf("Remain File Size is : %d \n", fileSize % 8);
remainingByte = fileSize % 8;
fileSize /= 8;
outputFile = new RandomAccessFile(fileName, "rw");
} catch (MalformedURLException ex) {
Logger.getLogger(DownloadInfo.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(DownloadInfo.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.printf("File Name is : %s\n", fileName);
System.out.printf("File Extension is : %s\n", fileExtension);
System.out.printf("Partition Size is : %d MB\n", fileSize);
int first = 0 , last = fileSize - 1;
ExecutorService thread_pool = Executors.newFixedThreadPool(8);
for(int i=0;i<8;i++){
if(i != 7){
thread_pool.submit(new Downloader(nonStringUrl, first, last, (i+1), outputFile));
}
else{
thread_pool.submit(new Downloader(nonStringUrl, first, last + remainingByte, (i+1), outputFile));
}
first = last + 1;
last += fileSize;
}
thread_pool.shutdown();
try {
thread_pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
Logger.getLogger(DownloadInfo.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
and this is my downloader class:
package download.manager;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author Behzad
*/
public class Downloader implements Runnable{
private URL downloadURL;
private int startByte;
private int endByte;
private int threadNum;
private RandomAccessFile outputFile;
private InputStream stream;
public Downloader(URL downloadURL,int startByte, int endByte, int threadNum, RandomAccessFile outputFile) {
this.downloadURL = downloadURL;
this.startByte = startByte;
this.endByte = endByte;
this.threadNum = threadNum;
this.outputFile = outputFile;
}
#Override
public void run() {
download();
}
private void download(){
try {
System.out.printf("Thread %d is working...\n" , threadNum);
HttpURLConnection httpURLConnection = (HttpURLConnection) downloadURL.openConnection();
httpURLConnection.setRequestProperty("Range", "bytes="+startByte+"-"+endByte);
httpURLConnection.connect();
outputFile.seek(startByte);
stream = httpURLConnection.getInputStream();
while(true){
int nextByte = stream.read();
if(nextByte == -1){
break;
}
outputFile.write(endByte);
}
} catch (IOException ex) {
Logger.getLogger(Downloader.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
This file is MP4 for as you seen, but Gom can't play it
Would you please help me?
OoOoOopppps finally I found what is the problem , It's all on seek method. because i have a file and 8 threads. so seek method changes the cursor repeatedly and make larger file and unexecutable file :), But I'm so sorry . I can't show whole code :)
I have been asked to write a program that will read a file as it is updated (4 times/millisecond) and print the number of lines to the system. To do this, I have the following code:
package threadFile;
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
public class ReadFile
{
private String path;
public ReadFile(String file_name)
{
path = file_name;
}
public String[] OpenFile() throws IOException
{
FileReader fr = new FileReader(path);
BufferedReader textReader = new BufferedReader(fr);
int numberOfLines = readLines();
String[]textData = new String[numberOfLines];
int i;
for(i=0; i< numberOfLines; i++)
{
textData[i] = textReader.readLine();
}
textReader.close();
return textData;
}
#SuppressWarnings("unused")
int readLines() throws IOException
{
FileReader file_to_read = new FileReader(path);
BufferedReader bf = new BufferedReader(file_to_read);
String aLine;
int numberOfLines = 0;
while ((aLine = bf.readLine()) != null)
{
numberOfLines++;
}
bf.close();
return numberOfLines;
}
The above code is meant to open a text file and read the number of lines there are. My issue is, getting the program to update as the file is written to (by another section of the program).The below code is a thread, and is meant to call into ReadFile for instructions.
I need the program to constantly read the contents, and accurately update the line count as it is edited.
If I understand correctly your requirement you want to use one file for Inter Process Communication (or inter thread-communication to be more exact for your case). If this is the case you probably want to use the file as MemoryMapped file.
A simple description of MemoryMapped file usage is done here.
As it was already said, Java 1.7 Watch Service is also a solution that could work.
Solution
The solution to my problem was a little more involved than expected.
Reading Files
package threadFile;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class PrintReader implements Runnable
{
#SuppressWarnings("unused")
private final String taskName;
final String file_name = "C:/Users/wigginsm/Desktop/Log.txt";
public PrintReader(String name)
{
taskName = name;
}
public void run()
{
boolean loop = true;
while(loop = true)
try
{
FileReader fr = new FileReader(file_name);
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
int count = 0;
while(line!=null)
{
count++;
line=br.readLine();
}
FileInputStream fileIn = new FileInputStream(file_name);
BufferedReader fileR = new BufferedReader(new InputStreamReader(fileIn));
String strLine = null, tmp;
while((tmp = fileR.readLine())!=null)
{
strLine = tmp;
}
String lastLine = strLine;
System.out.println("Last entered line: " + lastLine + "\n" + "Total number of Lines: " + count);
br.close();
fileR.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
The above class is responsible for reading the file, declared with "file_name".
Writing to Files
package threadFile;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
public class WriteToFile implements Runnable
{
#SuppressWarnings("unused")
private final String taskName;
class WriteFile
{
private String path;
private boolean append_to_file = false;
public WriteFile(String file_path, boolean append_value)
{
path = file_path;
append_to_file = append_value;
}
public void writeToFile(String timestamp) throws IOException
{
int i = 0;
while(i<1)
{
FileWriter write = new FileWriter(path, append_to_file);
Calendar current = Calendar.getInstance();
int ms = current.get(Calendar.MILLISECOND);
int minute = current.get(Calendar.MINUTE);
int second = current.get(Calendar.SECOND);
int hour = current.get(Calendar.HOUR_OF_DAY);
int day = current.get(Calendar.DAY_OF_YEAR);
int month = current.get(Calendar.MONTH)+1;
int year = current.get(Calendar.YEAR);
timestamp = day + "/" + month + "/" + year + " " + hour + ":" + minute + ":" + second + ":" + ms;
PrintWriter print_line = new PrintWriter(write);
try
{
Thread.sleep(250);
}
catch(InterruptedException e)
{
Thread.currentThread().interrupt();
}
print_line.printf("%s" + "%n", timestamp);
print_line.close();
}
}
}
//constructor
public WriteToFile(String name)
{
taskName = name;
}
#SuppressWarnings("unused")
public synchronized void run()
{
boolean loop = true;
while(loop = true)
{
try
{
String file_name = "C:/Users/wigginsm/Desktop/Log.txt";
Calendar current = Calendar.getInstance();
int ms = current.get(Calendar.MILLISECOND);
int minute = current.get(Calendar.MINUTE);
int second = current.get(Calendar.SECOND);
int hour = current.get(Calendar.HOUR_OF_DAY);
int day = current.get(Calendar.DAY_OF_YEAR);
int month = current.get(Calendar.MONTH)+1;
int year = current.get(Calendar.YEAR);
String timestamp = day + "/" + month + "/" + year + " " + hour + ":" + minute + ":" + second + ":" + ms;
WriteFile data = new WriteFile(file_name, true);
data.writeToFile(timestamp);
}
catch(IOException e)
{
System.out.println(e.getMessage());
}
}
}
}
The above code is responsible for writing to the file. The only reason for the while loop to continue indefinitely is due to my program specification. This can easily be altered to fit any iteration.
Execution
package threadFile;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class execute
{
public static void main(String[] args)
{
final String file_name = "C:/Users/wigginsm/Desktop/Log.txt";
WriteToFile writes = new WriteToFile(file_name);
PrintReader reads = new PrintReader(file_name);
ExecutorService thread = Executors.newCachedThreadPool();
thread.execute(reads);
thread.execute(writes);
thread.shutdown();
}
}
This is the main class, it is responsible for handling the threading. Both PrintWrite and WriteToFile have the "synchronize" statement, as run() in both classes accesses the file.