多文件自平衡云传输:核心部分:文件结构、目录存储,分发策略

之前将文件的存储做完了,但仍有一个坑就是当时记录的路径都是该文件相对于工程的路径,那么实际应用时为了能确切找到文件所要放的位置,就需要将绝对路径也存储起来,即ResourceStructor:

public class ResourceStructor {

	private String resourceId;
	private String absolutePath;
	private List<String> absoluteRootDirectories;
	private List<String> resourceDirectories;
	private List<ResourceFileInfo> fileList;
	private int index;

成员依次表示:
1.所处工程id
2.绝对路径
3.将绝对路径再分割后的路径列表(因为用户所给的绝对路径未必在该电脑上存在,而java生成文件时是不允许跨过一个不存在的文件夹去生成文件的。如:C://test//video,当用户电脑只存在C盘,没有test文件夹,但是工程是从video开始的,生成文件夹是就需要先提供C://test生成test文件夹,再提供C://test//video去生成video文件夹)
4.工程下各个文件夹相对于工程根文件夹的相对路径
5.该工程下所有文件
6.方便遍历所有文件

每个成员的生成:

void setAbsolutePath(String absolutePath) {
		this.absoluteRootDirectories.clear();
		String[] dirs = absolutePath.split("\\\\");
		String tmp = dirs[0] + "\\";
		for (int i = 1; i < dirs.length; i++) {
			tmp += dirs[i] + "\\";
			this.absoluteRootDirectories.add(tmp);
		}
		
		this.absolutePath = absolutePath;
	}

在设置好绝对路径的同时要将绝对路径划分开来生成absoluteRootDirectories。

其余成员都是在扫描该工程时生成的:

void scanAbsolutePath() throws Exception {
		if (this.absolutePath == null) {
			throw new Exception("资源绝对根未设置!");
		}
		File rootFile = new File(this.absolutePath);
		if (!rootFile.exists()) {
			throw new Exception("资源绝对根不存在!");
		}
		ResourceStructor.tmpIndex = 0;
		scanAbsolutePath(rootFile);
	}
private void scanAbsolutePath(File curDir) {
		File[] files = curDir.listFiles();
		
		if (files.length <= 0) {
			return;
		}
		
		for (int index = 0; index < files.length; index++) {
			File file = files[index];
			if (file.isDirectory()) {
				String dirPath = file.getAbsolutePath();
				this.resourceDirectories.add(dirPath.replace(this.absolutePath, ""));
				scanAbsolutePath(file);
			} else {
				String filePath = file.getAbsolutePath();
				
				ResourceFileInfo fileInfo = new ResourceFileInfo();
				fileInfo.setFileName(filePath.replace(this.absolutePath, ""));
				fileInfo.setFileSize(file.length());
				fileInfo.setFileNo(ResourceStructor.tmpIndex ++);
				
				this.fileList.add(fileInfo);
			}
		}
	}

用户给绝对跟后,扫描绝对跟下的所有文件、文件夹,若是文件夹,则需要将其路径删去绝对路径再加入resourceDirectories成员,若是文件则可生成一个新的ResourceFileInfo加入fileList成员。

上述文件结构、目录存储的目的是在未来传输时,在接收端的处理更加合理,网络传输的难点也是在这里,作为资源拥有者,其所要传输的文件工程的路径都是已知的,但是到了资源请求者这边,工程所处的资源环境是完全不同的,那么第一步就是要依据传来的文件结构生成一套空的文件夹作为后续文件接受的准备工作。

public class RequestResourceStructor {
	private String resourceId;
	private String absolutePath;
	private List<String> absoluteRootDirectories;
	private List<String> resourceDirectories;
	private List<ResourceFileInfo> fileList;
	private int index;
	
	private ResourceStructor orgResourceStructor;
	private IResourceDistributeStrategy resourceDistributeStrategy;
	private List<ResourceFileSectionInfo> resourceFileSectionList;

这是资源请求者的文件结构存储类,该类成员与资源拥有者的相关类大同小异,只是多了三个成员:
1.原始文件结构(因为请求方的文件结构并不完整,需要依照发送过来的原始结构进行生产)
2.资源分发策略:该成员将在后续资源分发时解释(实际是将大文件分块的过程)
3.文件资源列表

该类构造方法:

public RequestResourceStructor(ResourceStructor orgResourceStructor) {
		this.fileList = new ArrayList<ResourceFileInfo>();
		this.index = 0;
		this.orgResourceStructor = orgResourceStructor;
		
		this.resourceId = orgResourceStructor.getResourceId();
		this.absolutePath = orgResourceStructor.getAbsolutePath();
		this.absoluteRootDirectories = orgResourceStructor.getAbsoluteRootDirectories();
		this.resourceDirectories = orgResourceStructor.getResourceDirectories();
	}

如上文所说,该类需要借由发送过来的原始文件结构进行生成。

在接收方机器上的准备工作:

public void preparedRequestResource() {
		createResourceDirectories();
		
		while (this.orgResourceStructor.hasNext()) {
			ResourceFileInfo resFile = this.orgResourceStructor.next();
			String filePath = this.absolutePath + resFile.getFileName();
			
			File file = new File(filePath);
			if (!file.exists()) {
				this.fileList.add(resFile);
			}
		}
	}
private void createResourceDirectories() {
		for (String dirPath : this.absoluteRootDirectories) {
			File dirPathFile = new File(dirPath);
			if (!dirPathFile.exists()) {
				dirPathFile.mkdir();
			}
		}
		
		for (String dirPath : this.resourceDirectories) {
			File dirPathFile = new File(this.absolutePath + dirPath);
			if (!dirPathFile.exists()) {
				dirPathFile.mkdir();
			}
		}
	}

准备工作:
1.将工程的文件夹目录都生成出来,首先遍历分解后的根目录列表以此生成,再遍历资源文件夹列表并生成文件夹。
2.遍历原始文件列表,对其中的文件有两个处理结果:
①文件已存在,当文件在本机已经存在时,不需要再将其加入到文件结构中,即不用再次申请该文件的资源
②文件不存在,需要加入文件结构
这一步就可以看出本机的这个文件结构命名中的request作用,实际作用①生成所需接收环境 ②记录所要申请的文件

分发策略:

public List<ResourceFileSectionInfo> distribute(RequestResourceStructor resourceStructor, int senderCount) {
		List<ResourceFileSectionInfo> res = new ArrayList<ResourceFileSectionInfo>();
		for (int i = 0; i < senderCount; i++) {
			ResourceFileSectionInfo resourceFileSectionInfo = new ResourceFileSectionInfo();
			resourceFileSectionInfo.setResourceId(resourceStructor.getResourceId());
			res.add(resourceFileSectionInfo);
		}
		
		long offset;
		long currentLen;
		int senderIndex = 0;
		while (resourceStructor.hasNext()) {
			ResourceFileInfo fileInfo = resourceStructor.next();
			long fileSize = fileInfo.getFileSize();
			if (fileSize > this.maxFileLen) {
				offset = 0;
				while (fileSize > 0) {
					currentLen = fileSize > this.maxFileLen ? this.maxFileLen : fileSize;
					FileSectionInfo sectionInfo = new FileSectionInfo(fileInfo.getFileNo(),
							offset, currentLen);
					res.get(senderIndex).addFileSection(sectionInfo);
					senderIndex = (senderIndex + 1) % senderCount;
					
					offset += currentLen;
					fileSize -= currentLen;
				}
			} else {
				FileSectionInfo sectionInfo = new FileSectionInfo(fileInfo.getFileNo(), 0, fileInfo.getFileSize());
				res.get(senderIndex).addFileSection(sectionInfo);
				senderIndex = (senderIndex + 1) % senderCount;
			}
		}
		
		return res;
	}

文件分发策略主要是为了依据发送者个数,将所有请求文件分成多个块文件(即先前的32k、fileSection)。
首先需要请求者的文件结构和发送者个数。
第一步:依据发送者个数,生成一个文件列表(用于后续为每个发送者分配发送任务)
第二步:遍历文件结构下的文件列表,这一步就到了真正将文件分块的地方,设置一个最大文件块大小,当文件超过这个大小时,用FileSectionInfo存储一块,放到某个发送者任务下,并将记录的文件大小减小,直到分块结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔幻音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值