Java tutorial
/* * Copyright 2014 Napolov Dmitry * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.aotorrent.common.storage; import com.google.common.collect.Lists; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.aotorrent.common.TorrentFile; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Collection; import java.util.List; /** * User: dnapolov * Date: 11/25/13 * Time: 6:17 PM */ public class FileStorage { private final List<TorrentFile> files; private final int pieceLength; public FileStorage(List<TorrentFile> files, int pieceLength) { this.files = files; this.pieceLength = pieceLength; } public void store(int pieceIndex, ByteBuf byteBuffer) throws IOException { Collection<StorageFilesInfo> storageFiles = getAffectedFiles(pieceIndex); for (StorageFilesInfo storageFile : storageFiles) { ByteBuf buf = Unpooled.buffer((int) storageFile.getLength()); byteBuffer.getBytes((int) storageFile.getPieceOffset(), buf, (int) storageFile.getLength()); final File file = storageFile.getFile(); if (file.getParentFile() != null) { //noinspection ResultOfMethodCallIgnored file.getParentFile().mkdirs(); } try (RandomAccessFile randomAccessFile = new RandomAccessFile(file.getCanonicalPath(), "rw")) { try (FileChannel fileChannel = randomAccessFile.getChannel()) { fileChannel.position(storageFile.getFileOffset()); fileChannel.write(buf.nioBuffer()); } } } } public ByteBuf read(int pieceIndex, int length) throws IOException { Collection<StorageFilesInfo> storageFiles = getAffectedFiles(pieceIndex); ByteBuffer buf = ByteBuffer.allocate(length); for (StorageFilesInfo storageFile : storageFiles) { try (RandomAccessFile randomAccessFile = new RandomAccessFile(storageFile.getFile(), "r")) { try (FileChannel fileChannel = randomAccessFile.getChannel()) { ByteBuffer local = ByteBuffer.allocate((int) storageFile.getLength()); fileChannel.read(local, storageFile.getFileOffset()); local.flip(); buf.put(local); } } } buf.flip(); return Unpooled.wrappedBuffer(buf); } private Collection<StorageFilesInfo> getAffectedFiles(int pieceIndex) { long pieceStartPosition = ((long) pieceIndex) * pieceLength; long pieceEndPosition = pieceStartPosition + pieceLength; long fileStartPosition = 0; long fileEndPosition; int fileIndex = 0; List<StorageFilesInfo> storageFilesInfos = Lists.newArrayList(); while (fileIndex < files.size() && fileStartPosition < pieceEndPosition) { TorrentFile file = files.get(fileIndex); fileEndPosition = fileStartPosition + file.getLength(); StorageFilesInfo sfi = null; if ((fileStartPosition <= pieceStartPosition) && (fileEndPosition > pieceStartPosition)) { // file starts earlier than piece, but included in it if (fileEndPosition >= pieceEndPosition) { // file takes whole piece sfi = new StorageFilesInfo(new File(file.getPath()), 0, pieceStartPosition - fileStartPosition, pieceLength); } else if (fileEndPosition < pieceEndPosition) { // file takes first part of piece sfi = new StorageFilesInfo(new File(file.getPath()), 0, pieceStartPosition - fileStartPosition, fileEndPosition - pieceStartPosition); } } else if ((fileStartPosition > pieceStartPosition) && (fileEndPosition < pieceEndPosition)) { // whole file is in piece sfi = new StorageFilesInfo(new File(file.getPath()), fileStartPosition - pieceStartPosition, 0, file.getLength()); } else if ((fileStartPosition > pieceStartPosition) && (fileEndPosition > pieceEndPosition)) { // file ends the piece sfi = new StorageFilesInfo(new File(file.getPath()), fileStartPosition - pieceStartPosition, 0, pieceEndPosition - fileStartPosition); } if (sfi != null) { storageFilesInfos.add(sfi); } fileStartPosition = fileEndPosition; fileIndex++; } return storageFilesInfos; } private class StorageFilesInfo { private final File file; private final long pieceOffset; private final long fileOffset; private final long length; private StorageFilesInfo(File file, long pieceOffset, long fileOffset, long length) { this.file = file; this.pieceOffset = pieceOffset; //starting index of piece this.fileOffset = fileOffset; this.length = length; } public File getFile() { return file; } public long getPieceOffset() { return pieceOffset; } public long getFileOffset() { return fileOffset; } public long getLength() { return length; } } }