package volume

import (
    "time"
    "encoding/binary"
    "errors"
    "os"
    "io"
)
//文件基本信息结构体
type FileInfo struct {
    Fid      uint64
    Offset   uint64
    Size     uint64
    Ctime    time.Time
    Mtime    time.Time
    Atime    time.Time
    FileName string
}
//文件信息编码到切片中
func (iv *FileInfo)MarshalBinary() []byte {
    data := make([]byte, 48 + len(iv.FileName))
    binary.BigEndian.PutUint64(data[0:8], iv.Fid)
    binary.BigEndian.PutUint64(data[8:16], iv.Offset)
    binary.BigEndian.PutUint64(data[16:24], iv.Size)
    binary.BigEndian.PutUint64(data[24:32], uint64(iv.Ctime.Unix()))
    binary.BigEndian.PutUint64(data[32:40], uint64(iv.Mtime.Unix()))
    binary.BigEndian.PutUint64(data[40:48], uint64(iv.Atime.Unix()))
    copy(data[48:], []byte(iv.FileName))
    return data
}
//文件信息解码到结构体中
func (iv *FileInfo)UnMarshalBinary(data []byte) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = r.(error)
        }
    }()

    iv.Fid = binary.BigEndian.Uint64(data[0:8])
    iv.Offset = binary.BigEndian.Uint64(data[8:16])
    iv.Size = binary.BigEndian.Uint64(data[16:24])
    iv.Ctime = time.Unix(int64(binary.BigEndian.Uint64(data[24:32])), 0)
    iv.Mtime = time.Unix(int64(binary.BigEndian.Uint64(data[32:40])), 0)
    iv.Atime = time.Unix(int64(binary.BigEndian.Uint64(data[40:48])), 0)
    iv.FileName = string(data[48:])
    return err
}
//文件结构体
type File struct {
    DataFile *os.File
    Info     *FileInfo
    offset   uint64  //偏移量
}
//读取文件
func (f *File)Read(b []byte) (n int, err error) {
       //计算文件开始读取位置和结束位置
    start := f.Info.Offset + f.offset
    end := f.Info.Offset + f.Info.Size
    length := end - start
    if len(b) > int(length) {
        b = b[:length]
    }

    n, err = f.DataFile.ReadAt(b, int64(start))  //读取文件  从start位置开始 读取b个数据
    f.offset += uint64(n)
    if f.offset >= f.Info.Size {
        err = io.EOF
    }
    return
}
//写文件
func (f *File)Write(b []byte) (n int, err error) {
    start := f.Info.Offset + f.offset
    end := f.Info.Offset + f.Info.Size
    length := end - start
    if len(b) > int(length) {
        //b = b[:length]
        return 0, errors.New("you should create a new File to write")
    }else {
        n, err = f.DataFile.WriteAt(b, int64(start))
        f.offset += uint64(n)
        return
    }
}
//读取文件偏移量
//0意味着相对于文件的原始位置,1意味着相对于当前偏移量,2意味着相对于文件结尾
func (f *File)Seek(offset int64, whence int) (int64, error) {
    switch whence {
    case 0: 
        f.offset = uint64(offset)
    case 1:
        f.offset = uint64(int64(f.offset) + offset)
    case 2:
        f.offset = uint64(int64(f.Info.Size) + offset)
    }
    return int64(f.offset), nil
    //if f.offset > f.Info.Size {
    //    f.offset = 0
    //    return int64(f.offset), errors.New("offset > file.size")
    //}else {
    //    return int64(f.offset), nil
    //}
}

file.go的更多相关文章

  1. 记一个mvn奇怪错误: Archive for required library: 'D:/mvn/repos/junit/junit/3.8.1/junit-3.8.1.jar' in project 'xxx' cannot be read or is not a valid ZIP file

    我的maven 项目有一个红色感叹号, 而且Problems 存在 errors : Description Resource Path Location Type Archive for requi ...

  2. HTML中上传与读取图片或文件(input file)----在路上(25)

    input file相关知识简例 在此介绍的input file相关知识为: 上传照片及文件,其中包括单次上传.批量上传.删除照片.增加照片.读取图片.对上传的图片或文件的判断,比如限制图片的张数.限 ...

  3. logstash file输入,无输出原因与解决办法

    1.现象 很多同学在用logstash input 为file的时候,经常会出现如下问题:配置文件无误,logstash有时一直停留在等待输入的界面 2.解释 logstash作为日志分析的管道,在实 ...

  4. input[tyle="file"]样式修改及上传文件名显示

    默认的上传样式我们总觉得不太好看,根据需求总想改成和上下结构统一的风格…… 实现方法和思路: 1.在input元素外加a超链接标签 2.给a标签设置按钮样式 3.设置input[type='file' ...

  5. .NET平台开源项目速览(16)C#写PDF文件类库PDF File Writer介绍

    1年前,我在文章:这些.NET开源项目你知道吗?.NET平台开源文档与报表处理组件集合(三)中(第9个项目),给大家推荐了一个开源免费的PDF读写组件 PDFSharp,PDFSharp我2年前就看过 ...

  6. [笔记]HAproxy reload config file with uninterrupt session

    HAProxy is a high performance load balancer. It is very light-weight, and free, making it a great op ...

  7. VSCode调试go语言出现:exec: "gcc": executable file not found in %PATH%

    1.问题描述 由于安装VS15 Preview 5,搞的系统由重新安装一次:在用vscdoe编译go语言时,出现以下问题: # odbcexec: "gcc": executabl ...

  8. input type='file'上传控件假样式

    采用bootstrap框架样式 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> &l ...

  9. FILE文件流的中fopen、fread、fseek、fclose的使用

    FILE文件流用于对文件的快速操作,主要的操作函数有fopen.fseek.fread.fclose,在对文件结构比较清楚时使用这几个函数会比较快捷的得到文件中具体位置的数据,提取对我们有用的信息,满 ...

  10. ILJMALL project过程中遇到Fragment嵌套问题:IllegalArgumentException: Binary XML file line #23: Duplicate id

    出现场景:当点击"分类"再返回"首页"时,发生error退出   BUG描述:Caused by: java.lang.IllegalArgumentExcep ...

随机推荐

  1. 单片机PWM调制技术

    我们可以看看下图,下图就是一个典型的PWM的波形图. T是一个周期,T1就是高电平所占用的时间,T2就是低电平所占用的时间. 如上图所示T1为脉冲宽度(就是导通时间),周期为T,则输出电压的平均值为U ...

  2. Salesforce Lightning开发学习(一)Hello World开发实践

    一:什么是Lightning Component framework Lightning Component framework 简称Lightning,是Salesforce封装的一个前端框架,开发 ...

  3. python简单线程和协程学习

    python中对线程的支持的确不够,不过据说python有足够完备的异步网络框架模块,希望日后能学习到,这里就简单的对python中的线程做个总结 threading库可用来在单独的线程中执行任意的p ...

  4. box-sizing属性(指定针对元素的宽度与高度的计算方法)

    在css中,使用width属性与height属性来指定元素的宽度与高度.使用box-sizing属性,可以指定用width属性与height属性分别指定的宽度值与高度值是否包含元素的内部补白区域与边框 ...

  5. html5中新增的元素和废除的元素

    一.新增的结构元素 1.section元素表示页面中的一个内容区块,比如章节.页眉.页脚或页面中的其他部分.它可以与h1.h2.h3.h4.h5.h6等元素结合起来使用,标示文档结构. h5中的代码事 ...

  6. Scala编程入门---数组操作之数组转换

    使用yield和函数式编程转换数组 //对Array进行转换,获取的还是Aarry val a = Array(1,2,3,4,5) val a2 = for(ele <- a) yield e ...

  7. 【python进阶】深入理解系统进程1

    前言 之前程序执⾏都是⼀条腿⾛路,甚⾄是⽤⼀杆枪来打天下. 通过系统编程的学习,会让⼤家有“多条腿”⼀起⾛路,就好⽐有了⼀把机关枪. 此篇为深入理解进程第一篇,下面开始今天的说明~~~ 进程 多任务的 ...

  8. nginx基本配置参数说明

    #运行用户 user nobody; #启动进程,通常设置成和cpu的数量相等 worker_processes 1; #全局错误日志及PID文件 #error_log logs/error.log; ...

  9. Python 基础【二】 上

    一.python语言分类 1. C python   c语言的python版本 官方推荐 使用C语言实现,使用最为广泛,CPython实现会将源文件(py文件)转换成字节码文件(pyc文件),然后运行 ...

  10. 修改ZendStudio新建php文件时的模板

    zendstudio默认的模板不适用,可以自己到Window -- preferences -- php -- code style -- code templates -- code -- samp ...