How to use ttorrent to create a torrent file? - java

I'm starting to use ttorrent (Turn's BitTorrent Java library) to create a local network synchronized folder.
My goal is to use the torrent protocol do sync large files in nodes hard drives.
But I can't see how to create a new torrent file using ttorrent.
I need to:
1) A new file is added to one node.
2) Other nodes receive the torent file and start do download this file from the first node or pieces from other nodes that already downloaded that file part, speeding the downloading time. This way I can avoid each node to download gigabytes from a server (and wait all day).
I can't go ahead without knowing how to create a torrent file for that new added file (or if a better and smart way exists).
I can have a central point to serve as tracker.
Thanks.

Thanks to fujohnwang
public class Main {
public static void main(String[] args) {
// File parent = new File("d:/echo-insurance.backup");
String sharedFile = "d:/echo-insurance.backup";
try {
Tracker tracker = new Tracker( InetAddress.getLocalHost() );
tracker.start();
System.out.println("Tracker running.");
System.out.println( "create new .torrent metainfo file..." );
Torrent torrent = Torrent.create(new File(sharedFile), tracker.getAnnounceUrl().toURI(), "createdByDarren");
System.out.println("save .torrent to file...");
FileOutputStream fos = new FileOutputStream("d:/seed.torrent");
torrent.save( fos );
fos.close();
} catch ( Exception e ) {
e.printStackTrace();
}
}
}

Related

Create a binary file in java

These are the related questions that might cause my question to be closed, even though I specify another question:
Java: How to write binary files? -> Doesn't really cover the point that I am talking about
create a binary file -> Absolutely doesn't cover the point
Editing a binary file in java -> They are talking about offsets and stuff, when I just need to write the data and stop
Binary files in java -> Vague.
And now to the point. I've got a file with a specific extension, to be more exact it's .nbs. I want to create a file and then write the specific data to it.
That might have sounded vague so let me show you the code I have started with.
try {
File bpdn = new File(getDataFolder() + "song.nbs");
if (!bpdn.exists()) {
bpdn.createNewFile();
}
FileOutputStream fos = new FileOutputStream(bpdn);
} catch (IOException e) {
e.printStackTrace();
}
I'll provide you even more details. So I've got a song.nbs file that I have created in the past, for myself. And now, whenever a person runs my application, I want it so there's a new song.nbs file with the exact contents of a file that I have on my PC right now. Therefore, I need to somehow get the bytes of my existing song.nbs and then copy and paste them in my Java application... or is it the way? I neither know how to get the bytes of my own file right now, nor do I know how to write them.
You need to create a resources folder. More info here.
Assuming your project structure is
ProjectName/src/main/java/Main.java
you can create a resources folder inside main/:
ProjectName/src/main/java/Main.java
ProjectName/src/main/resources/
Move your song.nbs you want to read inside resources/:
ProjectName/src/main/java/Main.java
ProjectName/src/main/resources/song.nbs
Now, get the InputStream of song.nbs stored there:
final ClassLoader classloader = Thread.currentThread().getContextClassLoader();
final InputStream is = classloader.getResourceAsStream("song.nbs");
Then, write this input stream to your new file:
final File bpdn = new File(getDataFolder() + "song.nbs");
if (!bpdn.exists()) bpdn.createNewFile();
final FileOutputStream os = new FileOutputStream(bpdn);
byte[] buffer = new byte[1024];
int read;
while ((read = is.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
I think I came up with a solution, but I am not sure if this is works. I'd appreciate if you would take a look.
try {
File bpdn = new File(getDataFolder() + "badpiggiesdrip.nbs");
if (!bpdn.exists()) {
bpdn.createNewFile();
}
FileOutputStream fos = new FileOutputStream(bpdn);
fos.write(new byte[] {
Byte.parseByte(Arrays.toString(Base64.getDecoder().decode(Common.myString)))
});
} catch (IOException e) {
e.printStackTrace();
}
Common.myString is just a string, that contains data of this type:
(byte) 0x21, (byte) 0x5a, .....
and it's encoded in Base64.

Get ZIP first entry name from remote FTP Server without downloading the zip using Java 8+

I am using FTPClient to download files from my FTP Server , it's full of zip folders that contain from one to many .txt files inside . They can be huge in size like ... 10GB .
What i want to do is without downloading the zip archive from FTP read the name of the first .txt file it has . It's guarranted it will have at least 1 .txt file inside it.
I read a very interesting article here but it's in .NET and they are using remote URL which is different from my situation .
zip format defines some kind of directory pointing to all its inner entries. Containing properties like names, starting offset, size, and other stuff. And that this directory is pretty small, just a few bytes placed on the very end of the archive.
How i can play around it with FTPCient ?
I did the following , as far as i see there is not other answer .
Example imput ("ftp-folder/input.txt") :
public String getZipFirstEntryName(final String remotePath) {
this.log.info("ENTERING getZipFirstEntry, remotePath={} ", remotePath);
/* Setup FTP connection */
final FTPClient ftpClient = this.setupFtpConnection();
try {
ftpClient.changeWorkingDirectory(remotePath.split("/")[0]); /* ftp-folder */
} catch (final IOException e) {
e.printStackTrace();
}
try (final ZipArchiveInputStream zip = new ZipArchiveInputStream(ftpClient.retrieveFileStream(remotePath.split("/")[1]))) { /* input.txt */
this.log.info("EXITING getZipFirstEntry, remotePath={} ", remotePath);
return zip.getNextEntry().getName();
} catch (final IOException e) {
e.printStackTrace();
}
}

Database Import and Export not working in Android Pie

Below is the working method to Import and Export SQLite database. Its Working just fine in all android versions excluding Android Pie. When I am trying to import in Android pie, it shows successful toast but database is not being restored. Can anybody help me workaround in Android Pie(API 28).
private void importDB() {
try {
File sd = Environment.getExternalStorageDirectory();
File cur_db_pat = new File(this.getDatabasePath(DATABASE_NAME).getAbsolutePath());
if (sd.canWrite()) {
String backupDBPath = bac_dir_nam +"/" + DATABASE_NAME;
File currentDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(cur_db_pat).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getBaseContext(), cur_db_pat.toString(),
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
.show();
}
}
private void exportDB() {
try {
File sd = Environment.getExternalStorageDirectory();
File cur_db_pat = new File(this.getDatabasePath(DATABASE_NAME).getAbsolutePath());
if (sd.canWrite()) {
String backupDBPath = bac_dir_nam+"/" + DATABASE_NAME;
File backupDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(cur_db_pat).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getBaseContext(), backupDB.toString(),
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
.show();
}
}
I don't have much experience with file system. So an example would help a lot.
In Android Pie+ SQLite has changed to default to using the generally more efficient Write Ahead Logging (WAL) instead of Journal mode.
As such there will be two files with the same name as the database but suffixed with -shm (shared memory file) and -wal (write ahead log) and their presence is what I believe causes the issue(s).
Temporary Files Used By SQLite (see 2.2 and 2.3)
One fix would be to disable Write Ahead Logging using use the SQliteDatabase disableWriteAheadLogging method and the previous method would work as before but with the less efficient journal mode.
(if using a subclass of SQliteOpenHelper then override the onConfigure method to invoke this method. ) disableWriteAheadLogging.
Another fix is to delete these two files when restoring. To avoid the potential for corruption you have to ensure that the database was adequately checkpointed before making the backup. see PRAGMA checkpoint;
The following is a snippet that deletes these two files when restoring (noting that the backup is assumed to have been taken with adequate checkpointing):-
// Added for Android 9+ to delete shm and wal file if they exist
File dbshm = new File(dbfile.getPath() + "-shm");
File dbwal = new File(dbfile.getPath()+ "-wal");
if (dbshm.exists()) {
dbshm.delete();
}
if (dbwal.exists()) {
dbwal.delete();
}
Another fix would be to additionally backup and subsequently restore the -shm and -wal files.
You may also wish considering the potential benefits of renaming the original files when importing/restoring, checking the new files after they have been copied (e.g. using PRAGMA integrity_check;) if the results indicat no issues then delete the renamed original files, otherwise delete the imported files and rename the original files to their original name, indicating that the import failed.
In your class for Db WorkHelper ovverride onOpen() method and set disableWriteAheadLogging then call onOpen() standard, if version of android sdk 28 , sure then old version remain old modality.
#Override
public void onOpen(SQLiteDatabase database) {
super.onOpen(database);
if(Build.VERSION.SDK_INT >= 28)
{
database.disableWriteAheadLogging();
}
}
In my case WORK perfect.
Unlike what the other commenters have suggested, you can't rely on the database consisting of a single file after write-ahead logging is disabled, and you can't assume that the -shl and -wal filenames remain correct. This is all an implementation detail of sqlite3 / Android and therefore subject to change at any time (just like the old code broke).
One way of doing this that I expect to continue working is to use sqlite3's .dump command to convert the database into SQL that can later be executed in order to recreate the database.
I haven't tested the following, but expect that something similar to it should work:
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
// Untested:
private byte[] exportDatabase(SQLiteDatabase database) throws IOException {
Process process = new ProcessBuilder()
.command("/system/bin/sqlite3", database.getPath(), ".dump")
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.start();
try (InputStream inputStream = process.getInputStream()) {
// [read the full contents of inputStream and save them somewhere]
return ByteStreams.toByteArray(inputStream);
} finally {
waitForProcess(process);
}
}
private void importDatabase(String databasePath, InputStream backedUpData) throws IOException {
// restore the database:
Process process = new ProcessBuilder()
.command("/system/bin/sqlite3", databasePath)
.redirectInput(ProcessBuilder.Redirect.PIPE)
.start();
try (OutputStream outputStream = process.getOutputStream()) {
// now write the backed-up contents back to outputStream
ByteStreams.copy(backedUpData, outputStream);
}
waitForProcess(process);
}
private static void waitForProcess(Process process) {
try {
process.waitFor();
} catch (InterruptedException e) {
// ignore interruption, restore interrupt flag
Thread.currentThread().interrupt();
}
}
Obviously, you'll have to ensure that:
The database that you're backing up isn't currently open.
The database that you're restoring doesn't already exist.

How do you send an html file along with its images through a socket in java

I'm required for a project to send an html file through a socket in Java. I managed to get the text to appear in the browser but none of the pictures load. I found this code online to help me send the html file in the first place, but I am wondering if there is any way to send the pictures. I have all of the images in an img folder, which is where the html file is located.
public class SimpleFileServer {
public final static int SOCKET_PORT = 9000; // you may change this
public final static String FILE_TO_SEND = "D:\\Project 2\\index.html"; // you may change this
public static void main (String [] args ) throws IOException {
FileInputStream fis = null;
BufferedInputStream bis = null;
OutputStream os = null;
ServerSocket servsock = null;
Socket sock = null;
try {
servsock = new ServerSocket(SOCKET_PORT);
while (true) {
try {
sock = servsock.accept();
// send file
File myFile = new File (FILE_TO_SEND);
byte [] mybytearray = new byte [(int)myFile.length()];
fis = new FileInputStream(myFile);
bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
os = sock.getOutputStream();
os.write(mybytearray,0,mybytearray.length);
System.out.println("Done.");
} finally {
if (bis != null) bis.close();
if (os != null) os.close();
if (sock!=null) sock.close();
}
}
} finally {
if (servsock != null) servsock.close();
}
}
}
Are you sure your project does not also require you to parse the HTML and request the images separately? It sounds like you're simulating something like a web server. Generally speaking a browser will download the HTML of a page, parse it, then send follow-up requests to the server for each image or other resource (CSS, off-site Javascript, etc.) contained in the page.
Doing one request per resource can also simplify your server, because it only has to deal with the resource being requested at the time, which pushes some of the logic and complication back onto the client to be able to know which resources to ask for.
Things have changed somewhat in HTTP 2, but that's another matter that is probably outside the scope of your question.
Typically, image files are not included in the html download, but are requested subsequently as the html file is parsed. The problem of why the images are not showing in your case can probably be fixed by correcting the src locations in the tags. IF you do need to download everything together though, I would recommend sending a .zip archive
I think you are trying to achieve the "save as" functionality in web browsers.
You need to save the html file separately and the assets such as image files, embedded contents separately.
Since you already have the images in img folder, you need to alter the src attribute of image tag in the html - to pick the images from the image folder.

Resume a Java FTP file download

I'm developing, in Java, an application that has to download from a server to client some very large files. So far I'm using the apache commons-net:
FileOutputStream out = new FileOutputStream(file);
client.retrieveFile(filename, out);
The connection commonly fails before the client finishes downloading the file. I need a way to resume the download of the file from the point where the connection failed, without downloading the whole file again, is it possible?
Things to know:
FileOutputStream has an append parameter, from doc;
#param append if true, then bytes will be written
to the end of the file rather than the beginning
FileClient has setRestartOffset which takes offset as parameter, from doc;
#param offset The offset into the remote file at which to start the
next file transfer. This must be a value greater than or
equal to zero.
We need to combine these two;
boolean downloadFile(String remoteFilePath, String localFilePath) {
try {
File localFile = new File(localFilePath);
if (localFile.exists()) {
// If file exist set append=true, set ofset localFile size and resume
OutputStream fos = new FileOutputStream(localFile, true);
ftp.setRestartOffset(localFile.length());
ftp.retrieveFile(remoteFilePath, fos);
} else {
// Create file with directories if necessary(safer) and start download
localFile.getParentFile().mkdirs();
localFile.createNewFile();
val fos = new FileOutputStream(localFile);
ftp.retrieveFile(remoteFilePath, fos);
}
} catch (Exception ex) {
System.out.println("Could not download file " + ex.getMessage());
return false;
}
}
Commons-net FTPClient supports restarting transfers from a specific offset. You'll have to keep track of what you've successfully retrieved, send the correct offset, and manage appending to the existing file. Assuming, of course, that the FTP server you're connecting to supports the REST (restart) command.

Categories