webrtc录制视频后端保存java后端代码
package com.graceup.webrtc;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* Servlet implementation class UploadServlet
*/
@WebServlet("/upload3")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 上传文件存储目录
private static final String UPLOAD_DIRECTORY = "upload";
// 上传配置
private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB
private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 使用 GBK 设置中文正常显示
response.setCharacterEncoding("GBK");
response.getWriter().write("菜鸟教程:http://www.runoob.com");
}
/**
* 上传数据及保存文件
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 检测是否为多媒体上传
if (!ServletFileUpload.isMultipartContent(request)) {
// 如果不是则停止
PrintWriter writer = response.getWriter();
writer.println("Error: 表单必须包含 enctype=multipart/form-data");
writer.flush();
return;
}
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 设置临时存储目录
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大文件上传值
upload.setFileSizeMax(MAX_FILE_SIZE);
// 设置最大请求值 (包含文件和表单数据)
upload.setSizeMax(MAX_REQUEST_SIZE);
// 中文处理
upload.setHeaderEncoding("UTF-8");
// 构造临时路径来存储上传的文件
// 这个路径相对当前应用的目录
String uploadPath = getServletContext().getRealPath("/") + File.separator + UPLOAD_DIRECTORY;
System.out.println(uploadPath);
// 如果目录不存在则创建
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
try {
// 解析请求的内容提取文件数据
@SuppressWarnings("unchecked")
List<FileItem> formItems = upload.parseRequest(request);
if (formItems != null && formItems.size() > 0) {
// 迭代表单数据
for (FileItem item : formItems) {
// 处理不在表单中的字段
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = uploadPath + File.separator + fileName;
//File storeFile = new File(filePath);
// 在控制台输出文件的上传路径
//System.out.println(filePath);
// 保存文件到硬盘
//item.write(storeFile);
appendHexFile(filePath, item.get());
request.setAttribute("message",
"文件上传成功!");
}
}
}
} catch (Exception ex) {
request.setAttribute("message",
"错误信息: " + ex.getMessage());
}
// 跳转到 message.jsp
// getServletContext().getRequestDispatcher("/message.jsp").forward(
// request, response);
response.setCharacterEncoding("UTF-8");
response.getWriter().write("菜鸟教程:本次上传成功");
}
private void appendHexFile(String fna, byte[] ba) {
long nano = System.nanoTime();
long mills = System.currentTimeMillis();
try {
File fa = new File(fna);
// RandomAccessFile ra = new RandomAccessFile(fa, "rw");
BufferedRandomAccessFile ra = new BufferedRandomAccessFile(fa, "rw");
ra.seek(fa.length());
ra.write(ba);
ra.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("### appendHexFile ~ cost:"+(System.nanoTime()-nano)+"ns "+(System.currentTimeMillis()-mills)+"ms");
}
}
package com.graceup.webrtc;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
public final class BufferedRandomAccessFile extends RandomAccessFile
{
static final int LogBuffSz_ = 16; // 64K buffer
static final int BuffSz_ = (1 << LogBuffSz_);
static final long BuffMask_ = ~(((long) BuffSz_) - 1L);
private String path_;
/* https://www.cnblogs.com/622698abc/archive/2013/08/18/3265584.html
* This implementation is based on the buffer implementation in Modula-3's
* "Rd", "Wr", "RdClass", and "WrClass" interfaces.
*/
private boolean dirty_; // true iff unflushed bytes exist
private boolean syncNeeded_; // dirty_ can be cleared by e.g. seek, so track sync separately
private long curr_; // current position in file
private long lo_, hi_; // bounds on characters in "buff"
private byte[] buff_; // local buffer
private long maxHi_; // this.lo + this.buff.length
private boolean hitEOF_; // buffer contains last file block?
private long diskPos_; // disk position
public BufferedRandomAccessFile(File file, String mode) throws IOException
{
this(file, mode, 0);
}
public BufferedRandomAccessFile(File file, String mode, int size) throws IOException
{
super(file, mode);
path_ = file.getAbsolutePath();
this.init(size);
}
public BufferedRandomAccessFile(String name, String mode) throws IOException
{
this(name, mode, 0);
}
public BufferedRandomAccessFile(String name, String mode, int size) throws FileNotFoundException
{
super(name, mode);
path_ = name;
this.init(size);
}
private void init(int size)
{
this.dirty_ = false;
this.lo_ = this.curr_ = this.hi_ = 0;
this.buff_ = (size > BuffSz_) ? new byte[size] : new byte[BuffSz_];
this.maxHi_ = (long) BuffSz_;
this.hitEOF_ = false;
this.diskPos_ = 0L;
}
public String getPath()
{
return path_;
}
public void sync() throws IOException
{
if (syncNeeded_)
{
flush();
getChannel().force(true);
syncNeeded_ = false;
}
}
// public boolean isEOF() throws IOException
// {
// assert getFilePointer() <= length();
// return getFilePointer() == length();
// }
public void close() throws IOException
{
this.flush();
this.buff_ = null;
super.close();
}
public void flush() throws IOException
{
this.flushBuffer();
}
private void flushBuffer() throws IOException
{
if (this.dirty_)
{
if (this.diskPos_ != this.lo_)
super.seek(this.lo_);
int len = (int) (this.curr_ - this.lo_);
super.write(this.buff_, 0, len);
this.diskPos_ = this.curr_;
this.dirty_ = false;
}
}
private int fillBuffer() throws IOException
{
int cnt = 0;
int rem = this.buff_.length;
while (rem > 0)
{
int n = super.read(this.buff_, cnt, rem);
if (n < 0)
break;
cnt += n;
rem -= n;
}
if ( (cnt < 0) && (this.hitEOF_ = (cnt < this.buff_.length)) )
{
// make sure buffer that wasn't read is initialized with -1
Arrays.fill(this.buff_, cnt, this.buff_.length, (byte) 0xff);
}
this.diskPos_ += cnt;
return cnt;
}
/*
* This method positions <code>this.curr</code> at position <code>pos</code>.
* If <code>pos</code> does not fall in the current buffer, it flushes the
* current buffer and loads the correct one.<p>
*
* On exit from this routine <code>this.curr == this.hi</code> iff <code>pos</code>
* is at or past the end-of-file, which can only happen if the file was
* opened in read-only mode.
*/
public void seek(long pos) throws IOException
{
if (pos >= this.hi_ || pos < this.lo_)
{
// seeking outside of current buffer -- flush and read
this.flushBuffer();
this.lo_ = pos & BuffMask_; // start at BuffSz boundary
this.maxHi_ = this.lo_ + (long) this.buff_.length;
if (this.diskPos_ != this.lo_)
{
super.seek(this.lo_);
this.diskPos_ = this.lo_;
}
int n = this.fillBuffer();
this.hi_ = this.lo_ + (long) n;
}
else
{
// seeking inside current buffer -- no read required
if (pos < this.curr_)
{
// if seeking backwards, we must flush to maintain V4
this.flushBuffer();
}
}
this.curr_ = pos;
}
public long getFilePointer()
{
return this.curr_;
}
public long length() throws IOException
{
// max accounts for the case where we have written past the old file length, but not yet flushed our buffer
return Math.max(this.curr_, super.length());
}
public int read() throws IOException
{
if (this.curr_ >= this.hi_)
{
// test for EOF
// if (this.hi < this.maxHi) return -1;
if (this.hitEOF_)
return -1;
// slow path -- read another buffer
this.seek(this.curr_);
if (this.curr_ == this.hi_)
return -1;
}
byte res = this.buff_[(int) (this.curr_ - this.lo_)];
this.curr_++;
return ((int) res) & 0xFF; // convert byte -> int
}
public int read(byte[] b) throws IOException
{
return this.read(b, 0, b.length);
}
public int read(byte[] b, int off, int len) throws IOException
{
if (this.curr_ >= this.hi_)
{
// test for EOF
// if (this.hi < this.maxHi) return -1;
if (this.hitEOF_)
return -1;
// slow path -- read another buffer
this.seek(this.curr_);
if (this.curr_ == this.hi_)
return -1;
}
len = Math.min(len, (int) (this.hi_ - this.curr_));
int buffOff = (int) (this.curr_ - this.lo_);
System.arraycopy(this.buff_, buffOff, b, off, len);
this.curr_ += len;
return len;
}
public void write(int b) throws IOException
{
if (this.curr_ >= this.hi_)
{
if (this.hitEOF_ && this.hi_ < this.maxHi_)
{
// at EOF -- bump "hi"
this.hi_++;
}
else
{
// slow path -- write current buffer; read next one
this.seek(this.curr_);
if (this.curr_ == this.hi_)
{
// appending to EOF -- bump "hi"
this.hi_++;
}
}
}
this.buff_[(int) (this.curr_ - this.lo_)] = (byte) b;
this.curr_++;
this.dirty_ = true;
syncNeeded_ = true;
}
public void write(byte[] b) throws IOException
{
this.write(b, 0, b.length);
}
public void write(byte[] b, int off, int len) throws IOException
{
while (len > 0)
{
int n = this.writeAtMost(b, off, len);
off += n;
len -= n;
this.dirty_ = true;
syncNeeded_ = true;
}
}
/*
* Write at most "len" bytes to "b" starting at position "off", and return
* the number of bytes written.
*/
private int writeAtMost(byte[] b, int off, int len) throws IOException
{
if (this.curr_ >= this.hi_)
{
if (this.hitEOF_ && this.hi_ < this.maxHi_)
{
// at EOF -- bump "hi"
this.hi_ = this.maxHi_;
}
else
{
// slow path -- write current buffer; read next one
this.seek(this.curr_);
if (this.curr_ == this.hi_)
{
// appending to EOF -- bump "hi"
this.hi_ = this.maxHi_;
}
}
}
len = Math.min(len, (int) (this.hi_ - this.curr_));
int buffOff = (int) (this.curr_ - this.lo_);
System.arraycopy(b, off, this.buff_, buffOff, len);
this.curr_ += len;
return len;
}
}