zoukankan      html  css  js  c++  java
  • 哈希及文件操作

    1.哈希 hash

    在将文件操作的方法之前,我们先来对上节的知识做一个拓展,就是哈希算法,那么什么是哈希算法呢?

    (1)哈希:hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。

    这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间。

    哈希算法的输入可以是字符串,可以是数据,可以是任何文件,经过哈希运算后,都变成一个固定长度的输出,该输出就是哈希值。

    >>> hash('我爱你')
    3471388576844338423
    >>> hash('小猿圈')
    5000768010434506639
    

    如上所示,输入“我爱你”三个字,经过哈希运算后,会得到一个随机数列,而且不管你的输入文件多大,最后得到的结果都是这么一个固定长度的数列,即使你输入的是一部电影,输出也是这么大。

    (2)特性:

      1.不可逆性:在具备编码功能的同时,哈希算法也作为一种加密算法存在。即,你无法通过分析哈希值计算出源文件的样子。

      无论是什么形式,任意大小的输入,最终结果都是一串长度相等的随机数列,因此你无法通过哈希值来推断数据原本的样子。

      2.计算极快:不论是一个5G的电影还是一个5k的文件,运用哈希算法计算量都极小,很快就可以计算出哈希值。

    (3)用途:

    哈希算法的不可逆特性使其在以下领域使用广泛

    1. 密码,我们日常使用的各种电子密码本质上都是基于hash的,你不用担心支付宝的工作人员会把你的密码泄漏给第三方,因为你的登录密码是先经过 hash+各种复杂算法得出密文后 再存进支付宝的数据库里的

    2. 文件完整性校验,通过对文件进行hash,得出一段hash值 ,这样文件内容以后被修改了,hash值就会变。 MD5 Hash算法的”数字指纹”特性,使它成为应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5 checksum的命令。

    3. 数字签名,数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。

    此外,hash算法在区块链领域也使用广泛。

    (4)在Python中基于HASH的数据类型是dict (字典)和set (集合)。之前说到的字典查询速度极快,以及集合天生去重就是运用了hash的特性。以下可以作一下了解。

    1.dict查询速度快

    假设一个dict中有很多信息,dict会将每一个key进行哈希,将所有的哈希值按照从大到小的顺序放到一个列表中,如keys=[ -22,-10,11,23,99]

    当需要查找某个信息时,dict将被查找信息的key进行哈希,同一个输入值进行哈希得到的哈希值时相等的,因此只需再列表中找到这个哈希值,就能找到对应的value。

    那么问题来了,如果字典的数据比较小,计算机就能很快找到对应的值,但是如果字典中有几十亿条数据,怎么快速的找到对应的值呢?

    dict采用的是二分法查找,即将被查找信息的key的哈希值与列表的中间的值比较大小,这样就可以舍弃一半的值,这样搜索区间就小了很多,多进行几次这样的操作,很快就可以找到对应的值。

    这就是字典为何查询速度快的基本原理,当然真实的算法会复杂的多。

    2.set 天生去重

    因为每存一个值到set里时, 都要先经过hash,然后通过得出的这个hash值算出应该存在set里的哪个位置,存的时候会先检查那个位置上有没有值 ,

    有的话就对比是否相等,如果相等,则不再存储此值。 如果不相等(即为空),则把新值存在这。

    2.文件操作

    Python的文件操作基本通过以下步骤

    f = open(filename)  # 打开文件

    f.write("hello world")  # 写操作

    f.read( )  # 读操作

    f.close( )  # 保存并关闭文件

    常用操作模式

    python文件有三种基本的操作模式

    r 只读模式

    w 创建模式,不能读,用此模式操作,新的内容会覆盖旧的内容。即清空原来的内容,写入新的内容。

    a 追加模式 ,写入的内容会追加到文件最后

    只读模式

    f = open('filename.text', 'r')
    f.readline()  # 读一行内容
    content = f.read()  # 读所有剩下的内容
    print(content)
    f.close()

    创建模式

    f = open('filename.text', 'w')
    f.write('hello world')  # 此时该文件的内容为hello world(不管原文件内容是什么)
    f.close()

    追加模式

    f = open('filename.text', 'a')
    f.write("小猿圈")  # 此时文件内容为 hello world小猿圈
    f.close()

    循环文件

    f = open('filename.tesxt' , 'r')
    for line in f:  # 遍历文件的每一行
        print(line) 

    文件的其他操作功能

    f = open('filename.text', 'r')
    
    f.mode  # 返回文件的打开方式
    
    f.name  # 返回文件名
    
    f.fileno()  # 返回文件句柄在内核中的索引值,以后做IO多路复用时可以用到
    
    f.flush()  #将内容写入硬盘时,由于硬盘的处理速度慢,内容会先在内存中,达到一定数量一# 起写入硬盘提升效率,flush()方法可将内存中的数据写入硬盘
    
    f.readable()  # 判断文件是否可读
    
    f.readline()  # 只读一行,遇到
     或 
    为止
    
    f.seek()  # 把操作文件的光标移动到指定位置  seek的长度是按字节算的 不同的编码方式每 #个字符所占的字节不同。如gbk编码下中文字符占两个字节,utf-8编码下中文字符占三个字 #节,如果读取文件时的编码方式不同会导致错误产生。
    
    f.seekable()  # 判断文件是否能进行 seek 操作
    
    f.tell()  # 返回当前文件操作光标的位置
    
    f.truncate()  # 按指定长度截取文件 
    # 指定长度的话,就从文件开头开始截断指定长度;
    # 不指定长度的话,就从光标当前位置到文件 # 尾部的内容全去掉。
    
    f.writeable()  # 判断文件是否可写

    混合模式

    文件打开还有三种混合模式,既可以读也可以写。

    w+ 写读 ,它会创建一个新文件 ,写一段内容,可以再把写的内容读出来,一般不用。

    r+ 读写,能读能写,但都是写在文件最后,跟追加一样,用的较多。

    a+ 追加读,文件一打开时光标会在文件尾部,写的数据全会是追加的形式。

    w+模式

     f=open('filename.text','w+')  # w+读取时 光标在最后一行 读取时需要指定光标
     f.write("alex 23 male")
     f.seek(0)  # 将光标移至开头 再读取
     print(f.readline())
     f.close()

    r+模式

    f = open('filename', 'r+')
    f.write()  # 默认往文件尾部写
    f.readline()  # 读的是第一行

    r+模式会将内容自动往文件末尾写,但是如果想修改数据应该怎么办?

    将光标移动到中间的某一个位置,插入一个信息,会发现原来的信息会被写入的信息所覆盖。原因是,当你将文件存到硬盘上时,就在硬盘上划分了一段空间,空间就那么大,当你想写入新的内容时,就只能覆盖掉原来的数据,而不能使数据整体向后移。

    如果想要修改文件,就只能将文件加载到内存当中,数据在内存当中可以随便增删改查,之后再将修改完的数据存入硬盘覆盖掉原来的数据,就完成了文件的修改。

     注:r+使用时,该文件必须存在。

    当你想修改一份特别大的文件的时候,一下把文件加载到内存,是一种不明智的方式。如果想不占内存,可以采用一边读一边写的方式,就是创建一个新的文件,一边从原文件中读,一边写入新的文件。

    f_name = "filename.txt"
    f_new_name = "%s.new" % f_name
    old_str = "eric"
    new_str = "alex"
    f = open(f_name,'r')  # 打开原文件
    f_new = open(f_new_name,'w')  # 创建一个新文件
    for line in f:  # 读原文件
        if old_str in line: 
            new_line = line.replace(old_str,new_str)  # 修改文件
        else:
            new_line = line
        f_new.write(new_line)  写入新文件
    f.close()
    f_new.close()

    注:以上内容部分参考自路飞学城。

  • 相关阅读:
    家庭内网向导帮助文档
    Nginx 容器连接 php rc-fpm 容器编译 php
    samba 容器实现共享
    编程思想(POP,OOP,SOA,AOP)
    OOP(面向对象编程)
    MySql5.6 Window超详细安装教程
    JAVA设计模式:状态模式
    Mysql设置创建时间字段和更新时间字段自动获取时间,填充时间
    eclipse里新建work set,将项目分组放在不同文件夹
    错误记录
  • 原文地址:https://www.cnblogs.com/sxy-blog/p/11932528.html
Copyright © 2011-2022 走看看