附加到文件,然后从中读取到列表中,然后重新附加到文件并覆盖某些部分

时间:2016-06-16 19:22:13

标签: python

我希望能够有一个程序,用户可以输入段落/句子/单词/字符,并将其存储在列表中,例如在列表[0]中。然后我希望他们能够写下另一段文字并将其存储在例如列表[1]。然后,在任何时候,我希望用户能够通过选择他们想要读取的片段从列表中读取该片段,例如,从列表[0]中读取“hello”,同时在列表[1]中存储“hi”。然后,当用户退出程序时,我希望将列表写入外部文件。然后,在下次启动时,程序应该读取文件内容并将其再次存储在列表中,以便用户可以添加更多位文本或读取当前位。当列表保存到文件时,它应该附加新的或更改的部分,但覆盖相同的部分,以便不重复。我没有取得太大的成功。说实话,我不确定是否有可能。我浏览了类似的论坛,并发现它没有多大帮助,所以在这里。

到目前为止我的代码:

    import os
    import time
    import csv

    global write_list
    global f1_contents
    write_list = []


    def write():
        os.system("cls")
        user_story = input("Enter your text: \n")
        write_list.append(user_story)


    def read():
        os.system("cls")
        user_select_needs = True
        while user_select_needs == True:
            user_select = input("Enter the list section to read from or type exit: \n")
            if user_select == "exit":
                user_select_needs = False
            try:
                int(user_select)
                select = user_select
                select = int(select)
                try:
                    print(write_list[select])
                    user_select_needs = False
                    enter = input("Press enter:")
                except:
                    print("There is not stored data on that section!")           
            except ValueError:
                print("That is not a valid section!")



    def exit():
        os.system("cls")
        max_num_needs = True
        while max_num_needs == True:
            set_max_num = input("Set the storage: \n")
            try:
                int(set_max_num)
                max_num = set_max_num
                max_num = int(max_num)
                max_num_needs = False
            except:
                print("It must be an integer!")
        for i in range(0, max_num):
        f = open("Saves.txt", "a")
        f.write(write_list[i])
        f.close()
        os._exit(1)


    def main():
        store_num_needs = True
        while store_num_needs == True:
            set_store_num = input("State the current storage amount: \n")
            try:
                int(set_store_num)
                store_num = set_store_num
                store_num = int(store_num)
                store_num_needs = False
            except:
                print("It must be an integer!")
        try:
            f1 = open("Saves.txt", "r")
            for i in range(0, store_num+1):
                i, = f1.split("#")
            f1.close()
        except:
            print("--------Loading-------")
            time.sleep(1)    
        while True:
            os.system("cls")
            user_choice = ""
            print("Main Menu" + "\n" + "---------")
            print("1) Write")
            print("2) Read")
            print("3) Exit")
            while user_choice not in ["1", "2", "3"]:
                user_choice = input("Pick 1, 2 or 3 \n")
            if user_choice == "1":
                write()
            elif user_choice == "2":
                read()
            else:
                exit()

    if __name__ == "__main__":
        main()

理解起来可能太复杂了,在哪种情况下只是在评论中问我 - 否则一般提示也会很好。

提前致谢

1 个答案:

答案 0 :(得分:1)

快速纠正:

仅当您在非全局上下文中定义全局变量时,才需要

global。换句话说,在默认缩进级别定义的任何内容都可以通过其下面定义的其他内容访问。例如:

def set_global():
    x = 1

def use_global():
    x += 1

set_global()
try:
    use_global()
except Exception as e:
    # `use_global` doesn't know
    # about what `set_global` did
    print("ERROR: " + str(e))

# to resolve this we can set `x` to a
# default value in a global context:

x = 1

# or, if it were required, we
# could create a global variable

def make_global():
    global x
make_global()

# either will work fine

set_global()
use_global()
print(x) # prints 2

现在回答实际问题:

我还没有读过您编写的代码块(可能最好将其修改为将来的相关位),但这应该解决问题,因为我理解它,并且您描述了它。

import os
import sys

user_text = []
# login the user somehow
user_file = 'saves.txt'

def writelines(f, lines):
    """Write lines to file with new line characters"""
    f.writelines('\n'.join(lines))

def readlines(f):
    """Get lines from file split on new line characters"""
    text = f.read()
    return text.split('\n') if text else []

class _Choice(object):
    """Class that is equivalent to a set of choices

    Example:

    >>> class YesObj(Choice):
    >>>     options = ('y', 'yes')
    >>> Yes = YesObj()
    >>> assert Yes == 'yes'
    >>> assert Yes == 'y'
    >>> # assertions evaluate to True

    Override the `options` attribute to make use
    """
    allowed = ()
    def __eq__(self, other):
        try:
            s = str(other)
        except:
            raise TypeError("Cannot compare with non-string")
        else:
            return s.lower() in self.allowed

def _choice_repr(choices):
    allowed = []
    for c in choices:
        if isinstance(c, _Choice):
            allowed.extend(c.allowed)
        else:
            allowed.append(c)
    if len(allowed) > 2:
        s = ', '.join([repr(c) for c in allowed[:-1]])
        s += ', or %s' % repr(allowed[-1])
    elif len(allowed) == 1:
        s = '%s or %s' % allowed
    else:
        s = '%s' % allowed[0]
    return s

def _choice_sentinel(name, allowed):
    """Creates a sentinel for comparing options"""
    return type(name, (_Choice,), {'allowed': list(allowed)})()

Quit = _choice_sentinel('Quit', ('q', 'quit'))
Yes = _choice_sentinel('Yes', ('y', 'yes'))
No = _choice_sentinel('No', ('n', 'no'))


def readline_generator(f):
    """Generate a file's lines one at a time"""
    t = f.readline()
    # while the line isn't empty
    while bool(t):
        yield t
        t = f.readline()

def read_from_cache():
    """Overwrite `user_text` with file content"""
    if not os.path.isfile(user_file):
        open(user_file, 'w').close()
        globals()['user_text'] = []
    else:
        with open(user_file, 'r') as f:
            lines = readlines(f)
            # replace vs extend user text
            for i, t in enumerate(lines):
                if i == len(user_text):
                    user_text.extend(lines[i:])
                else:
                    user_text[i] = t

def write_to_cache():
    """Overwrite cache after the first line disagrees with current text

    If modifications have been made near the end of the file, this will
    be more efficient than a blindly overwriting the cache."""
    with open(user_file, 'r+') as f:
        i = -1
        last_pos = f.tell()
        # enumerate is a generator, not complete list
        for i, t in enumerate(readline_generator(f)):
            if user_text[i] != t:
                # rewind to the line before
                # this diff was encountered
                f.seek(last_pos)
                # set the index back one in
                # order to catch the change
                i -= 1
                break
            last_pos = f.tell()

        # then cut off remainder of file
        f.truncate()

        # recall that i is the index of the diff

        # replace the rest of it with new
        # (and potentially old) content
        writelines(f, user_text[i+1:])

def blind_write_to_cache():
    """Blindly overwrite the cache with current text"""
    with open(user_file, 'w') as f:
        writelines(f, user_text)

def overwrite_user_text(i, text, save=False):
    """Overwrite a line of text

    If `save` is True, then these changes are cached
    """
    try:
        user_text[i] = text
    except IndexError:
        raise IndexError("No text exists on line %r" % (i+1))
    if save:
        write_to_cache()

def user_input():
    """Get a new line from the user"""
    return raw_input("input text: ")

def user_choice(msg, choices):
    if len(choices) == 0:
        raise ValueError("No choices were given")
    ans = raw_input(msg)
    if ans not in choices:
        print("Invalid Response: '%s'" % ans)
        m = "Respond with %s: " % _choice_repr(choices)
        return user_choice(m, choices)
    else:
        return ans

def user_appends():
    """User adds a new line"""
    user_text.append(user_input())

def user_reads(*args, **kwargs):
    """Print a set of lines for the user

    Selects text via `user_text[slice(*args)]`
    Use 'print_init' in kwargs to choose how
    many lines are printed out before user must
    scroll by pressing enter, or quit with 'q'."""
    print_init = kwargs.get('print_init', 4)
    sliced = user_text[slice(*args)]
    if not isinstance(sliced, list):
        sliced = [sliced]
    for i, l in enumerate(sliced):
        if i < print_init:
            print(l)
            sys.stdout.flush()
        elif user_choice(l, ['', Quit]) == Quit:
            break

def user_changes(i=None, save=False):
    """User changes a preexisting line"""
    attempt = True
    while i is None and attempt:
        # get the line the user wants to change
        i_text = raw_input("Line to be changed: ")
        try:
            # make user input an index
            i = int(i_text)
        except:
            # check if they want to try again
            c = user_choice("Bad input - '%s' is not an "
                "integer. Try again? " % i_text, (Yes, No))
            attempt = (c == Yes)
    if attempt:
        # user gave a valid integer for indexing
        try:
            user_reads(i-1)
            overwrite_user_text(i-1, user_input(), save)
        except Exception as e:
            print("ERROR: %s" % e)
            if user_choice("Try again? ", (Yes, No)):
                user_changes(i, save)


# stores whatever text is already on
# file to `user_text` before use
read_from_cache()