151 lines
3.5 KiB
Java
151 lines
3.5 KiB
Java
|
package us.shandian.giga.io;
|
||
|
|
||
|
import android.content.ContentResolver;
|
||
|
import android.net.Uri;
|
||
|
import android.os.ParcelFileDescriptor;
|
||
|
import android.util.Log;
|
||
|
|
||
|
import androidx.annotation.NonNull;
|
||
|
|
||
|
import org.schabi.newpipe.streams.io.SharpStream;
|
||
|
|
||
|
import java.io.FileInputStream;
|
||
|
import java.io.FileOutputStream;
|
||
|
import java.io.IOException;
|
||
|
import java.nio.channels.FileChannel;
|
||
|
|
||
|
public class FileStreamSAF extends SharpStream {
|
||
|
|
||
|
private final FileInputStream in;
|
||
|
private final FileOutputStream out;
|
||
|
private final FileChannel channel;
|
||
|
private final ParcelFileDescriptor file;
|
||
|
|
||
|
private boolean disposed;
|
||
|
|
||
|
public FileStreamSAF(@NonNull ContentResolver contentResolver, Uri fileUri) throws IOException {
|
||
|
// Notes:
|
||
|
// the file must exists first
|
||
|
// ¡read-write mode must allow seek!
|
||
|
// It is not guaranteed to work with files in the cloud (virtual files), tested in local storage devices
|
||
|
|
||
|
file = contentResolver.openFileDescriptor(fileUri, "rw");
|
||
|
|
||
|
if (file == null) {
|
||
|
throw new IOException("Cannot get the ParcelFileDescriptor for " + fileUri.toString());
|
||
|
}
|
||
|
|
||
|
in = new FileInputStream(file.getFileDescriptor());
|
||
|
out = new FileOutputStream(file.getFileDescriptor());
|
||
|
channel = out.getChannel();// or use in.getChannel()
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int read() throws IOException {
|
||
|
return in.read();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int read(byte[] buffer) throws IOException {
|
||
|
return in.read(buffer);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int read(byte[] buffer, int offset, int count) throws IOException {
|
||
|
return in.read(buffer, offset, count);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public long skip(long amount) throws IOException {
|
||
|
return in.skip(amount);// ¿or use channel.position(channel.position() + amount)?
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public long available() {
|
||
|
try {
|
||
|
return in.available();
|
||
|
} catch (IOException e) {
|
||
|
return 0;// ¡but not -1!
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void rewind() throws IOException {
|
||
|
seek(0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void close() {
|
||
|
try {
|
||
|
disposed = true;
|
||
|
|
||
|
file.close();
|
||
|
in.close();
|
||
|
out.close();
|
||
|
channel.close();
|
||
|
} catch (IOException e) {
|
||
|
Log.e("FileStreamSAF", "close() error", e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean isClosed() {
|
||
|
return disposed;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean canRewind() {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean canRead() {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean canWrite() {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean canSetLength() {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean canSeek() {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void write(byte value) throws IOException {
|
||
|
out.write(value);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void write(byte[] buffer) throws IOException {
|
||
|
out.write(buffer);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void write(byte[] buffer, int offset, int count) throws IOException {
|
||
|
out.write(buffer, offset, count);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setLength(long length) throws IOException {
|
||
|
channel.truncate(length);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void seek(long offset) throws IOException {
|
||
|
channel.position(offset);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public long length() throws IOException {
|
||
|
return channel.size();
|
||
|
}
|
||
|
}
|