拷贝多层文件

代码块

package com.example.panshuang.test;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

/**
 * Created by pan.shuang on 2020/8/11.
 */

public class NaviOfflineDataActivity extends Activity {
    private static final String TAG = "NaviOfflineDataActivity";
    private static final String FROM_FOLDER_PATH = "/storage/usbotg/AutoNaviData/chn";
    private static final String TO_FOLDER_PATH = "/navi/AutoNaviData/chn";

    private static final String FROM_MD5_FOLDER_PATH = "/storage/usbotg/AutoNaviData/md5";
    private static final String FROM_COPY_MD5_FOLDER_PATH = "/navi/AutoNaviData/md5";
    private static final String TO_MD5_FOLDER_PATH = "/navi/md5";

    private static final String MD5_FILE_NAME = "chnmd5.txt";

    private static final String FROM_MD5_FILE_PATH = FROM_MD5_FOLDER_PATH + "/" + MD5_FILE_NAME;
    private static final String FROM_COPY_MD5_FILE_PATH = FROM_COPY_MD5_FOLDER_PATH + "/" + MD5_FILE_NAME;
    private static final String TO_MD5_FILE_PATH = TO_MD5_FOLDER_PATH + "/" + MD5_FILE_NAME;


    private static final int MUIL_CLICK_DURATION = 500;
    long mLastClickTime;
    int mClickCount;
    boolean mIsVisiable;


    Button mCopyButton;
    Button mDeleteButton;
    Button mMD5Button;
    Button mCreateMD5Button;
    Button mCopyMD5Button;
    Button mForceStopButton;
    TextView mTextView;
    AlertDialog mAlertDialog;

    Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.navi_offline_data_layout);

        mHandler = new Handler();

        //显示操作状态,连续点击10次可显示或隐藏MD5生成、导入和强行停止选项
        mTextView = findViewById(R.id.copy_text);
        mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                long newClickTime = SystemClock.uptimeMillis();
                long duration = newClickTime - mLastClickTime;
                if (duration > 0 && duration < MUIL_CLICK_DURATION){
                    mClickCount ++;
                    if (mClickCount == 10){
                        mCreateMD5Button.setVisibility(mIsVisiable ? View.VISIBLE : View.GONE);
                        mCopyMD5Button.setVisibility(mIsVisiable ? View.VISIBLE : View.GONE);
                        mForceStopButton.setVisibility(mIsVisiable ? View.VISIBLE : View.GONE);
                        mClickCount = 0;
                        mIsVisiable = !mIsVisiable;
                    }
                }else {
                    mClickCount = 0;
                }
                mLastClickTime = SystemClock.uptimeMillis();
            }
        });

        //从U盘导入离线数据和MD5文件
        mCopyButton = findViewById(R.id.copy_button);
        mCopyButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mTextView.setText("拷贝中,请不要拔掉U盘");
                updateButtonClickable(false);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //先删除之前拷贝的
                        FileUtils.deleteFolderOrFile(TO_FOLDER_PATH);
                        FileUtils.deleteFolderOrFile(FROM_COPY_MD5_FILE_PATH);
                        FileUtils.deleteFolderOrFile(TO_MD5_FILE_PATH);
                        //然后先拷贝MD5文件,再拷贝正式文件
                        FileUtils.copyFile(FROM_MD5_FILE_PATH,FROM_COPY_MD5_FOLDER_PATH,MD5_FILE_NAME);
                        final int result = FileUtils.copyFolder(FROM_FOLDER_PATH, TO_FOLDER_PATH);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                updateTextView("拷贝",result);
                                updateButtonClickable(true);
                            }
                        });
                    }
                }).start();
            }
        });

        //删除离线数据和MD5文件
        mDeleteButton = findViewById(R.id.delete_button);
        mDeleteButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mTextView.setText("删除中");
                updateButtonClickable(false);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        FileUtils.deleteFolderOrFile(TO_MD5_FOLDER_PATH);
                        final int result = FileUtils.deleteFolderOrFile(TO_FOLDER_PATH);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                updateTextView("删除",result);
                                updateButtonClickable(true);
                            }
                        });
                    }
                }).start();
            }
        });

        //对离线数据进行MD5校验,即对离线数据生成MD5文件,并与导入的MD5文件进行比对(如果没有导入则实时对U盘离线数据生成MD5文件)
        mMD5Button = findViewById(R.id.md5_button);
        mMD5Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTextView.setText("MD5校验中");
                updateButtonClickable(false);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        final int result = FileUtils.compareMD5(FROM_FOLDER_PATH, TO_FOLDER_PATH, FROM_COPY_MD5_FOLDER_PATH, TO_MD5_FOLDER_PATH, MD5_FILE_NAME);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                updateTextView("MD5校验",result);
                                updateButtonClickable(true);
                            }
                        });
                    }
                }).start();
            }
        });

        //对U盘离线数据生成MD5文件至U盘
        mCreateMD5Button = findViewById(R.id.md5_create_button);
        mCreateMD5Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTextView.setText("MD5生成中,请不要拔掉U盘");
                updateButtonClickable(false);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        final int result = FileUtils.createMD5File(FROM_FOLDER_PATH, FROM_MD5_FOLDER_PATH,MD5_FILE_NAME);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                updateTextView("MD5生成",result);
                                updateButtonClickable(true);
                            }
                        });
                    }
                }).start();
            }
        });

        //从U盘导入MD5文件
        mCopyMD5Button = findViewById(R.id.md5_copy_button);
        mCopyMD5Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTextView.setText("MD5拷贝中,请不要拔掉U盘");
                updateButtonClickable(false);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        final int result = FileUtils.copyFile(FROM_MD5_FILE_PATH, FROM_COPY_MD5_FOLDER_PATH,MD5_FILE_NAME);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                updateTextView("MD5拷贝",result);
                                updateButtonClickable(true);
                            }
                        });
                    }
                }).start();
            }
        });

        //强行停止退出
        mForceStopButton = findViewById(R.id.stop_button);
        mForceStopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AlertDialog.Builder builder = new AlertDialog.Builder(NaviOfflineDataActivity.this);
                builder.setMessage("强行停止退出可能会导致未知异常,确定要这样做吗?");
                builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        System.exit(0);
                    }
                });
                builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        mAlertDialog.dismiss();
                    }
                });
                mAlertDialog = builder.create();
                mAlertDialog.show();
            }
        });
    }


    public void updateButtonClickable(boolean clickable){
        mCopyButton.setClickable(clickable);
        mDeleteButton.setClickable(clickable);
        mMD5Button.setClickable(clickable);
        mCreateMD5Button.setClickable(clickable);
        mCopyMD5Button.setClickable(clickable);
    }

    public void updateTextView(String start, int result){
        String text;
        switch (result){
            case FileUtils.CMD_RESULT_SUCCESS:
                text = start + "成功";
                break;
            case FileUtils.CMD_RESULT_FROM_FILE_NONEXIST:
                text = start + "失败,错误码:" + result +" 源文件不存在";
                break;
            case FileUtils.CMD_RESULT_TO_FILE_NONEXIST:
                text = start + "失败,错误码:" + result +" 目标文件不存在";
                break;
            case FileUtils.CMD_RESULT_FILE_NONSAME:
                text = start + "失败,错误码:" + result +" 文件不一致";
                break;
            case FileUtils.CMD_RESULT_ONWER_DIED:
                text = start + "失败,错误码:" + result +" 请确认U盘连接状态";
                break;
            default:
                text = start + "失败,错误码:" + result;
                break;
        }
        mTextView.setText(text);
    }
}

  1. 工具类
代码块
package com.example.panshuang.test;

import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

/**
 * Created by pan.shuang on 2020/8/12.
 */

public class FileUtils {
    public static final String TAG = "FileUtils";

    public static final int CMD_RESULT_UNKNOWN = -1;
    public static final int CMD_RESULT_FROM_FILE_NONEXIST = -2;
    public static final int CMD_RESULT_TO_FILE_NONEXIST = -3;
    public static final int CMD_RESULT_FILE_NONSAME = -4;
    public static final int CMD_RESULT_SUCCESS = 0;
    public static final int CMD_RESULT_PERMISSION_DENIED = 13;
    public static final int CMD_RESULT_ONWER_DIED = 130;


    public static int copyFile(String fromFilePath, String toFolderPath, String toFileName) {
        String toFilePath = toFolderPath + "/" + toFileName;
        Log.d(TAG, "copyFile from " + fromFilePath + " to "+toFilePath);
        int result;
        try {
            File fromFile = new File(fromFilePath);
            if (!fromFile.exists() || fromFile.length() == 0 || fromFile.isDirectory() || !fromFile.isFile() || !fromFile.canRead()){
                Log.e(TAG, "copyFile: " + fromFilePath + " usb file not exist.");
                result = CMD_RESULT_FROM_FILE_NONEXIST;
                return result;
            }
            Runtime runtime = Runtime.getRuntime();
            if (!(new File(toFolderPath).exists())) {
                java.lang.Process process = runtime.exec("mkdir -p " + toFolderPath);
                process.waitFor();
            }
            java.lang.Process process = runtime.exec("cp " + fromFilePath + " " + toFilePath);
            result = process.waitFor();
            Log.d(TAG, "result=" + result);
            if (result == 0) {
                Log.d(TAG, "copyFile completed from fromFilePath to " + toFolderPath);
            } else {
                Log.d(TAG, "copyFile fail " + toFolderPath);
            }
        } catch (Exception e) {
            Log.e(TAG, "copyFile "+ e.toString());
            result = CMD_RESULT_UNKNOWN;
        }
        return result;
    }


    public static int copyFolder(String fromFolderPath, String toFolderPath) {
        Log.d(TAG, "copyFolder from " + fromFolderPath + " to " + toFolderPath);
        int result;
        try {
            File fromFile = new File(fromFolderPath);
            if (!fromFile.exists() || fromFile.length() == 0 || !fromFile.canRead()) {
                Log.e(TAG, "copyFolder: " + fromFolderPath + " usb file not exist.");
                result = CMD_RESULT_FROM_FILE_NONEXIST;
                return result;
            }
            Runtime runtime = Runtime.getRuntime();
            if (!(new File(toFolderPath).exists())) {
                java.lang.Process process = runtime.exec("mkdir -p " + toFolderPath);
                process.waitFor();
            }
            java.lang.Process process = runtime.exec("cp -r " + fromFolderPath + "/. " + toFolderPath);
            result = process.waitFor();
            Log.d(TAG, "result=" + result);
            if (result == 0) {
                Log.d(TAG, "copyFolder completed from fromFilePath to " + toFolderPath);
            } else {
                Log.d(TAG, "copyFolder fail " + toFolderPath);
            }
        } catch (Exception e) {
            Log.e(TAG, "copyFolder " + e.toString());
            result = CMD_RESULT_UNKNOWN;
        }
        return result;
    }

    public static int deleteFolderOrFile(String deletePath) {
        Log.d(TAG, "deleteFolderOrFile " + deletePath);
        int result;
        try {
            File deleteFile = new File(deletePath);
            if (!deleteFile.exists() || deleteFile.length() == 0 || !deleteFile.canRead()) {
                result = CMD_RESULT_TO_FILE_NONEXIST;
                return result;
            }
            Runtime runtime = Runtime.getRuntime();
            java.lang.Process process = runtime.exec("rm -rf " + deletePath);
            result = process.waitFor();
            Log.d(TAG, "result=" + result);
            if (result == 0) {
                Log.d(TAG, "deleteFolderOrFile completed");
            } else {
                Log.d(TAG, "deleteFolderOrFile fail " + deletePath);
            }
        } catch (Exception e) {
            Log.e(TAG, "deleteFolderOrFile " + e.toString());
            result = CMD_RESULT_UNKNOWN;
        }
        return result;
    }

    public static int compareMD5(String fromFolderPath, String toFolderPath, String fromMD5FolderPath, String toMD5FolderPath, String MD5FileName) {
        Log.d(TAG, "compareMD5 from " + fromFolderPath + " to " + toFolderPath);
        String fromMD5FilePath = fromMD5FolderPath + "/" + MD5FileName;
        String toMD5FilePath = toMD5FolderPath + "/" + MD5FileName;
        int result;
        java.lang.Process process;
        try {
            Runtime runtime = Runtime.getRuntime();

            //先判断目标文件是否存在
            File toFile = new File(toFolderPath);
            if (!toFile.exists() || toFile.length() == 0 || !toFile.canRead()) {
                result = CMD_RESULT_TO_FILE_NONEXIST;
                return result;
            }

            //生成目标文件MD5文件夹
            if (!(new File(toMD5FolderPath).exists())) {
                process = runtime.exec("mkdir -p " + toMD5FolderPath);
                process.waitFor();
            }
            //生成目标文件MD5文件
            process = runtime.exec(new String[]{"sh","-c","find " + toFolderPath +
                    " -type f -print0 | xargs -0 md5sum | sort > " + toMD5FilePath});
            result = process.waitFor();
            Log.d(TAG, "tomd5 result=" + result);

            //如果成功生成目标文件MD5文件则与源文件比对
            if (result == 0 && new File(toMD5FilePath).length() > 0) {
                Log.d(TAG, "tomd5 completed " + toFolderPath);

                //判断源文件MD5文件是否存在,不存在则实时从源文件生成
                File fromMD5File = new File(fromMD5FilePath);
                //不存在
                if (!fromMD5File.exists() || fromMD5File.length() == 0 || !fromMD5File.canRead() || fromMD5File.isDirectory()) {
                    //源文件是否存在
                    File fromFile = new File(fromFolderPath);
                    if (!fromFile.exists() || fromFile.length() == 0 || !fromFile.canRead()) {
                        result = CMD_RESULT_FROM_FILE_NONEXIST;
                        return result;
                    }

                    //生成源文件MD5文件夹
                    if (!(new File(fromMD5FolderPath).exists())) {
                        process = runtime.exec("mkdir -p " + fromMD5FolderPath);
                        process.waitFor();
                    }

                    //根据源文件生成MD5文件并保存
                    process = runtime.exec(new String[]{"sh","-c","find " + fromFolderPath +
                            " -type f -print0 | xargs -0 md5sum | sort > " + fromMD5FilePath});
                    result = process.waitFor();
                    Log.d(TAG, "frommd5 result=" + result);
                }

                //源文件MD5文件可用,开始比较
                if (result == 0 && new File(fromMD5FilePath).length() > 0) {
                    Log.d(TAG, "frommd5 completed " + fromFolderPath);

                    String fromMD5String = readFileContentStr(fromMD5FilePath);
                    String toMD5String = readFileContentStr(toMD5FilePath);
                    if (fromMD5String.equals(toMD5String)){
                        Log.d(TAG,"md5 is same");
                    }else {
                        result = CMD_RESULT_FILE_NONSAME;
                        Log.d(TAG,"md5 is not same");
                    }
                } else {
                    //生成异常,删除
                    deleteFolderOrFile(fromMD5FilePath);
                    Log.d(TAG, "frommd5 fail " + fromFolderPath);
                }
            } else {
                //生成异常,删除
                deleteFolderOrFile(toMD5FilePath);
                Log.d(TAG, "tomd5 fail " + toFolderPath);
            }
        } catch (Exception e) {
            Log.e(TAG, "getMD5 " + e.toString());
            result = CMD_RESULT_UNKNOWN;
        }
        return result;
    }

    public static int createMD5File(String folderPath, String MD5FolderPath,  String MD5FileName) {
        Log.d(TAG, "createMD5File folderPath " + folderPath + " MD5FolderPath " + MD5FolderPath + "MD5FileName " + MD5FileName);
        String MD5FilePath = MD5FolderPath + "/" + MD5FileName;
        int result;
        java.lang.Process process;
        try {
            Runtime runtime = Runtime.getRuntime();

            //源文件是否存在
            File fromFile = new File(folderPath);
            if (!fromFile.exists() || fromFile.length() == 0 || !fromFile.canRead()) {
                result = CMD_RESULT_FROM_FILE_NONEXIST;
                return result;
            }

            //生成源文件MD5文件夹
            if (!(new File(MD5FolderPath).exists())) {
                process = runtime.exec("mkdir -p " + MD5FolderPath);
                process.waitFor();
            }

            //根据源文件生成MD5文件并保存
            process = runtime.exec(new String[]{"sh","-c","find " + folderPath +
                    " -type f -print0 | xargs -0 md5sum | sort > " + MD5FilePath});
            result = process.waitFor();
            Log.d(TAG, "createMD5File result=" + result);
        } catch (Exception e) {
            Log.e(TAG, "createMD5File " + e.toString());
            result = CMD_RESULT_UNKNOWN;
        }
        return result;
    }


    public static String readFileContentStr(String fullFilename) {
        StringBuffer readOutStr = new StringBuffer();
        BufferedReader bufReader = null;
        try {
            bufReader = new BufferedReader(new FileReader(fullFilename));
            String line = "";
            while ((line = bufReader.readLine()) != null) {
                readOutStr.append(line.substring(0,32));
            }
            Log.d("readFileContentStr", "Successfully to read out string from file " + fullFilename);
        } catch (IOException e) {
            e.printStackTrace();
            Log.d("readFileContentStr", "Fail to read out string from file " + fullFilename);
        } finally {
            if (bufReader != null) {
                try {
                    bufReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return readOutStr.toString();
    }
}

  1. 布局
代码块
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/copy_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="导入导航离线数据和MD5文件"/>


    <Button
        android:id="@+id/md5_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="导航离线数据MD5校验"/>

    <Button
        android:id="@+id/delete_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="删除导航离线数据和MD5文件"/>


    <Button
        android:id="@+id/md5_create_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="生成MD5文件至U盘"
        android:visibility="gone"/>

    <Button
        android:id="@+id/md5_copy_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="导入MD5文件"
        android:visibility="gone"/>

    <Button
        android:id="@+id/stop_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="强行停止退出"
        android:visibility="gone"/>

    <TextView
        android:id="@+id/copy_text"
        android:gravity="left|center_vertical"
        android:layout_width="500dp"
        android:layout_height="100dp"
        android:textSize="30sp"
        android:background="@android:color/white"
        android:textColor="@android:color/black"/>

</LinearLayout>

  1. 第二种拷贝方式
代码块

public boolean copyFolder1(String oldPath, String newPath) {
        try {
            File newFile = new File(newPath);
            if (!newFile.exists()) {
                if (!newFile.mkdirs()) {
                    Log.e("--Method--", "copyFolder: cannot create directory.");
                    return false;
                }
            }
            File oldFile = new File(oldPath);
            String[] files = oldFile.list();
            File temp;
            for (String file : files) {
                if (oldPath.endsWith(File.separator)) {
                    temp = new File(oldPath + file);
                } else {
                    temp = new File(oldPath + File.separator + file);
                }

                if (temp.isDirectory()) {   //如果是子文件夹
                    copyFolder(oldPath + "/" + file, newPath + "/" + file);
                } else if (!temp.exists()) {
                    Log.e("--Method--", "copyFolder:  oldFile not exist.");
                    return false;
                } else if (!temp.isFile()) {
                    Log.e("--Method--", "copyFolder:  oldFile not file.");
                    return false;
                } else if (!temp.canRead()) {
                    Log.e("--Method--", "copyFolder:  oldFile cannot read.");
                    return false;
                } else {
                    FileInputStream fileInputStream = new FileInputStream(temp);
                    FileOutputStream fileOutputStream = new FileOutputStream(newPath + "/" + temp.getName());
                    byte[] buffer = new byte[1024];
                    int byteRead;
                    while ((byteRead = fileInputStream.read(buffer)) != -1) {
                        fileOutputStream.write(buffer, 0, byteRead);
                    }
                    fileInputStream.close();
                    fileOutputStream.flush();
                    fileOutputStream.close();
                }

            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354