Android——数据存储(二)(二十二)
1. SQLite数据库存储
1.1 知识点
(1)了解SQLite数据库的基本作用;
(2)掌握数据库操作辅助类:SQLiteDatabase的使用;
(3)可以使用命令操作SQLite数据库;
(4)可以完成数据库的CRUD操作;
(5)掌握数据库查询及Cursor接口的使用。
1.2 具体内容
在Android当中,本身提供了一种微型的嵌入式数据库叫做SQLite,同样可以执行SQL语句,对于不熟悉sql和jdbc的小伙伴,还是需要去自学一下。
下面我们首先使用一段代码演示如何取得数据库表操作。
package com.example.sqliteopenhelper;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;public class MySQLiteOpenHelper extends SQLiteOpenHelper {public static final String DATABASENAME="wancy";//数据库名称public static final int DATABASEVERSION=1;//版本号public static final String TABLENAME = "DH10";//数据库表名public MySQLiteOpenHelper(Context context) {super(context, DATABASENAME, null, DATABASEVERSION);// TODO Auto-generated constructor stub}@Overridepublic void onCreate(SQLiteDatabase db) {String sql = "create table "+TABLENAME+" (id INTEGER PRIMARY KEY,"+"name VARCHAR(50) NOT NULL,"+"birthday DATE NOT NULL)";db.execSQL(sql);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {String sql = "drop table if exists "+TABLENAME;//当退出的时候删除表db.execSQL(sql);this.onCreate(db);}}
以上要注意一点,在SQLite当中如果想要让某个字段自动增长,那么在创建表的时候使用“INTEGER PRIMARY KEY”声明即可。
那么这样的话一个数据库辅助类已经定义好了,那么我们下面在Activity当中去调用此类的方法。
package com.example.sqliteproject;import com.example.sqliteopenhelper.MySQLiteOpenHelper;import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;public class SQLiteActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_sqlite);MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);helper.getWritableDatabase();//表示以读写的形式打开数据库}}
现在已经取得了数据库的连接了,如果以上代码没有错误,运行之后就可以在文件列表当中找到数据表.FileExplorer/data/data/数据库辅助类所在的包/database。根据代码,可以发现,如果数据库不存在,那么会自动调用onCreate方法去创建表,如果数据库已经存在了,但是版本号发生了改变,将会调用onUpgrade方法,现将原来的表删除之后,在去创建新的表。
·使用SQLite数据库并完成数据库的更新操作。
public void insert(String name,String birthday){SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象String sql = "insert into "+TABLENAME+" (name,birthday) values ('"+name+"',"+birthday+")";db.execSQL(sql);db.close();}public void update(int id,String name,String birthday){SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象String sql = "update "+TABLENAME+" set name='"+name+"',birthday="+birthday+" where id="+id;db.execSQL(sql);db.close();}public void delete(int id){SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象String sql = "delete from "+TABLENAME+" where id="+id;db.execSQL(sql);db.close();}
以上增删改三个方法写完之后,就可以在Activity当中去进行调用。
package com.example.sqliteproject;import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;import com.example.sqliteopenhelper.MySQLiteOpenHelper;public class SQLiteActivity extends Activity {MySQLiteOpenHelper helper=null;Button insert,update,del = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_sqlite);insert=(Button) super.findViewById(R.id.insert);update = (Button) super.findViewById(R.id.update);del = (Button) super.findViewById(R.id.del);helper = new MySQLiteOpenHelper(this);helper.getWritableDatabase();//表示以读写的形式打开数据库insert.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {helper.insert("毛栗子", "1995-01-05");Toast.makeText(SQLiteActivity.this, "新增成功", 0).show();}});update.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {helper.update(1, "大白兔", "1995-01-05");Toast.makeText(SQLiteActivity.this, "修改成功", 0).show();}});del.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {helper.delete(1);Toast.makeText(SQLiteActivity.this, "删除成功", 0).show();}});}}
以上的程序,所有数据都是固定的,这在实际开发当中显然是不科学的,因为我们至少也要使用编辑框进行数据的编辑才是符合实际,而且使用字符串拼凑sql这种形式也是存在问题的,那么我们可以使用占位符的形式来处理这种问题。
public void insert(String name,String birthday){SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象java.sql.Date date = null;try {date = new java.sql.Date(new SimpleDateFormat("yyyy-MM-dd").parse(birthday).getTime());} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}String sql = "insert into "+TABLENAME+" (name,birthday) values (?,?)";//使用占位符Object args[] = new Object[]{name,birthday};db.execSQL(sql,args);db.close();}
对于以上程序,只是换了另一种操作方法来解决拼凑的问题,功能上没有变化。
对于拼凑sql和使用占位符,可以形成一个共识:
肯定是使用占位符更好一些。
在android当中,还对数据的封装提供了一个ContentValues类。 可以理解为一个Map集合,有key和value,唯一不同的是ContentValues中的key必须是字符串。以后的操作就可以直接通过key取得value。并将value设置到sql语句当中。
public void insert(String name,String birthday){SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象ContentValues cv = new ContentValues();cv.put("name", name);cv.put("birthday", birthday);db.insert(TABLENAME, null, cv);//进行新增操作db.close();}public void update(int id,String name,String birthday){SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象ContentValues cv = new ContentValues();cv.put("name", name);cv.put("birthday", birthday);String whereClause = " id=?";String whereArgs[]= new String[]{String.valueOf(id)};db.update(TABLENAME, cv, whereClause, whereArgs);//更新操作db.close();}public void delete(int id){SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象String whereClause = " id=?";String whereArgs[]= new String[]{String.valueOf(id)};db.delete(TABLENAME, whereClause, whereArgs);//删除操作db.close();}
那么对于使用占位符和ContentValues进行数据库更新操作,两种方式并没有严格的优劣之分,但是对于不会sql的开发人员来说,使用ContentValues更好的。
·数据库查询机Cursor接口
在JDBC中ResultSet接口不呢是的功能就是依靠一个next()方法一动指针向下取数据,是到了JDBC2.0之后才能够向上取数据,但是我们一般也不去用这种向上取的形式。
Cursor接口,出现的比ResultSet晚,所有操作机制有些不同。
package com.example.sqliteproject;import java.util.ArrayList;
import java.util.List;import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;public class DH10Cursor {private static final String TABLENAME="PR10";private SQLiteDatabase db =null;public DH10Cursor(SQLiteDatabase db) {super();this.db = db;}public List<String> find(){List<String> all = new ArrayList<String>();String sql = "select id,name,birthday from "+TABLENAME;Cursor result = this.db.rawQuery(sql, null);//执行查询语句//采用循环的形式去结果集中的数据for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){all.add(result.getInt(0)+"====="+result.getString(1)+"====="+result.getString(2));}result.close();db.close();return all;}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:id="@+id/mylayout"tools:context=".SQLiteActivity" ><Buttonandroid:id="@+id/insert"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="新增"/><Buttonandroid:id="@+id/update"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="修改"/><Buttonandroid:id="@+id/del"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="删除"/><Buttonandroid:id="@+id/query"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="查询"/></LinearLayout>
package com.example.sqliteproject;import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;import com.example.sqliteopenhelper.MySQLiteOpenHelper;public class SQLiteActivity extends Activity {MySQLiteOpenHelper helper=null;Button insert,update,del,query = null;ListView listView = null;LinearLayout myLayout = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_sqlite);helper = new MySQLiteOpenHelper(this);insert=(Button) super.findViewById(R.id.insert);update = (Button) super.findViewById(R.id.update);del = (Button) super.findViewById(R.id.del);query = (Button) super.findViewById(R.id.query);myLayout = (LinearLayout) super.findViewById(R.id.mylayout);query.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {SQLiteActivity.this.listView = new ListView(SQLiteActivity.this);listView.setAdapter(new ArrayAdapter<String>(SQLiteActivity.this, android.R.layout.simple_list_item_1,new DH10Cursor(SQLiteActivity.this.helper.getWritableDatabase()).find()));myLayout.addView(listView);}});insert.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {helper.insert("毛栗子", "1995-01-05");Toast.makeText(SQLiteActivity.this, "新增成功", 0).show();}});update.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {helper.update(1, "大白兔", "1995-01-05");Toast.makeText(SQLiteActivity.this, "修改成功", 0).show();}});del.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {helper.delete(1);Toast.makeText(SQLiteActivity.this, "删除成功", 0).show();}});}}
需要注意一下Cursor的下标是从0开始的有别于ResultSet
·模糊查询
·使用sql语句完成模糊查询
public List<String> find(){List<String> all = new ArrayList<String>();String sql = "select id,name,birthday from "+TABLENAME+" where name like ?";String args[] = new String[]{"%栗%"};Cursor result = this.db.rawQuery(sql, args);//执行查询语句//采用循环的形式去结果集中的数据for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){all.add(result.getInt(0)+"====="+result.getString(1)+"====="+result.getString(2));}result.close();db.close();return all;}
·使用query方法完成
public List<String> find(){List<String> all = new ArrayList<String>();//String sql = "select id,name,birthday from "+TABLENAME+" where name like ?";String selection = "name like ?";String args[] = new String[]{"%栗%"};String columns[] = new String[]{"id","name","birthday"};Cursor result = this.db.query(TABLENAME, columns, selection, args, null, null, null);//执行查询语句//采用循环的形式去结果集中的数据for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){all.add(result.getInt(0)+"====="+result.getString(1)+"====="+result.getString(2));}result.close();db.close();return all;}
既然模糊查询已经能够完成了,那么还有一种功能可以往下去实现,那就是数据的分页。如果想要实现数据的部分显示,这个语句和Mysql中的查询方式是非常相似,使用limit完成。下面我们进行一些简单的分页操作。
public List<String> find(){int currentPage = 1;//当前页码int lineSize = 5;//每页显示的数据量List<String> all = new ArrayList<String>();String sql = "select id,name,birthday from "+TABLENAME+" limit ?,?";String args[] = new String[]{String.valueOf((currentPage-1)*lineSize),String.valueOf(currentPage*lineSize)};Cursor result = this.db.rawQuery(sql, args);//采用循环的形式去结果集中的数据for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){all.add(result.getInt(0)+"====="+result.getString(1)+"====="+result.getString(2));}result.close();db.close();return all;}
·使用ListView来实现滑动分页
Android中有这样一个操作,只需要手指进行上下滑动,屏幕自动滚动,到达最后一条数据的时候,提示:请稍等,数据正在加载......。这个操作需要使用SimpleAdapter来完成,因为在这个适配器中有下面这样一个方法。
pulibc void notifyDataSetChanged()
表示如果在SimpleAdapter中的填充数据集合list内容一旦发生变化,就会立刻通知ListView进行及时新数据加载,当数据加载底部的时候,需要提示一个信息,而这个信息可以通过ListView组件里的方法去添加
public void addFooterView(View v)
现在还剩下一个问题,需要去监听滚动事件,需要使用如下接口:
首先顶一个ListView的布局模板。
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/mylayout"android:layout_width="match_parent"android:layout_height="match_parent" ><TableRow ><TextView android:id="@+id/id"android:layout_width="50px"android:layout_height="wrap_content"android:textSize="30px"/><TextView android:id="@+id/name"android:layout_width="120px"android:layout_height="wrap_content"android:textSize="30px"/><TextView android:id="@+id/birthday"android:layout_width="130px"android:layout_height="wrap_content"android:textSize="30px"/></TableRow></TableLayout>
现在我们需进行查询操作,需要返回一共有多少笔数据,修改一下查询的类
package com.example.sqliteproject;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;public class DH10Cursor {private static final String TABLENAME="DH10";private SQLiteDatabase db =null;public DH10Cursor(SQLiteDatabase db) {super();this.db = db;}public List<Map<String,Object>> find(int currentPage,int lineSize){List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();String sql = "select id,name,birthday from "+TABLENAME+" limit ?,?";String args[] = new String[]{String.valueOf((currentPage-1)*lineSize),String.valueOf(currentPage*lineSize)};Cursor result = this.db.rawQuery(sql, args);for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){Map<String,Object> map = new HashMap<String,Object>();map.put("id", result.getInt(0));map.put("name", result.getString(1));map.put("birthday", result.getString(2));list.add(map);}return list;}public int getCount(){int count = 0;String sql = "select count(id) from "+TABLENAME;Cursor result = this.db.rawQuery(sql, null);for(result.moveToFirst();!result.isAfterLast();result.moveToNext()){count = result.getInt(0);//取得数据的总笔数}return count;}
}
下面写一下主布局文件,这个比较简单,直接放一个线性布局管理器就可以了。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/mainlayout"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ></LinearLayout>
现在只剩下Activity
package com.example.sqliteproject;import java.util.List;
import java.util.Map;import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;import com.example.sqliteopenhelper.MySQLiteOpenHelper;public class SQLiteActivity extends Activity {MySQLiteOpenHelper helper=null;ListView listView = null;LinearLayout mainLayout = null;int currentPage = 1;int lineSize = 5;int count = 0;int pageSize = 1;//总页数int lastItem = 0;//保存最后一个记录点SimpleAdapter adapter = null;TextView tv = null;//底部信息LinearLayout loadLayout = null;//底部提示框布局List<Map<String,Object>> list = null;LayoutParams lp= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); super.setContentView(R.layout.listview_main);this.mainLayout=(LinearLayout) super.findViewById(R.id.mainlayout);this.loadLayout=new LinearLayout(this);this.tv = new TextView(this);tv.setText("数据加载中,请稍后。。。");tv.setGravity(Gravity.CENTER);tv.setTextSize(30);loadLayout.addView(this.tv,this.lp);loadLayout.setGravity(Gravity.CENTER);this.showAllData();}private void showAllData(){this.helper = new MySQLiteOpenHelper(this);this.listView = new ListView(this);DH10Cursor cursor = new DH10Cursor(this.helper.getWritableDatabase());//获得一个查询操作对象this.count = cursor.getCount();//取得总数据笔数this.list = cursor.find(currentPage, lineSize);this.adapter = new SimpleAdapter(this, list, R.layout.listview_item_layout, new String[]{"id","name","birthday"},new int[]{R.id.id,R.id.name,R.id.birthday});//实例化适配器对象SQLiteActivity.this.listView.addFooterView(SQLiteActivity.this.loadLayout);this.listView.setAdapter(adapter);this.listView.setOnScrollListener(new OnScrollListener() {@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if(SQLiteActivity.this.lastItem==SQLiteActivity.this.adapter.getCount()//表示当前记录已经在最底部&&SQLiteActivity.this.currentPage<SQLiteActivity.this.pageSize//当前页要小于总页数&&scrollState==OnScrollListener.SCROLL_STATE_IDLE//屏幕不再滚动){SQLiteActivity.this.currentPage++;SQLiteActivity.this.listView.setSelection(SQLiteActivity.this.lastItem);//设置显示位置SQLiteActivity.this.listView.addFooterView(SQLiteActivity.this.loadLayout);SQLiteActivity.this.appendData();}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {SQLiteActivity.this.lastItem = firstVisibleItem+visibleItemCount-1;}});mainLayout.addView(this.listView);if(this.count%this.lineSize==0){this.pageSize = this.count/this.lineSize;}else{this.pageSize = this.count/this.lineSize+1;}}private void appendData(){//更新数据方法DH10Cursor cursor = new DH10Cursor(this.helper.getWritableDatabase());List<Map<String,Object>> newData = cursor.find(currentPage, lineSize);this.list.addAll(newData);this.adapter.notifyDataSetChanged();//适配器重新加载集合数据}
}
以上就是整个实现下滑屏幕实现分页加载数据的程序。
事务的处理是针对数据库而已,以后的开发当中,只要针对增删改,都需要用事务进行处理。
public void insert(String name,String birthday){SQLiteDatabase db = super.getWritableDatabase();//取得数据库操作对象db.beginTransaction();//开启事务try{ContentValues cv = new ContentValues();cv.put("name", name);cv.put("birthday", birthday);db.insert(TABLENAME, null, cv);//进行新增操作db.setTransactionSuccessful();//正确执行,否则回滚}catch(Exception e){db.endTransaction();//事务关闭db.close();}}
1.3 小结
(1)SQLite数据库是一个专门用于嵌入式设备的数据库;
(2)SQLite支持SQL语句的操作;
(3)可以使用SQLiteOpenHelper类完成数据库的操作;
(4)所有的查询数据使用Cursor进行接收;
相关文章:

Android——数据存储(二)(二十二)
1. SQLite数据库存储 1.1 知识点 (1)了解SQLite数据库的基本作用; (2)掌握数据库操作辅助类:SQLiteDatabase的使用; (3)可以使用命令操作SQLite数据库; …...

appium环境搭建
一.appium环境搭建 1.python3 python3的下载安装这里就不多做介绍了,当然你也可以选择自己喜欢的语音,比如java… 2.jdk 1)下载地址 官网(需登录账号): https://www.oracle.com/java/technologies/downloads/ 百度网盘&…...

十五、Webpack打包图片-js-Vue、Label命令、resolve模块解析
一、webpack打包图片 (1)加载图片案例准备 为了演示我们项目中可以加载图片,我们需要在项目中使用图片,比较常见的使用图片的方式是两种: img元素,设置src属性;其他元素(比如div&…...

ARM指令集--数据处理指令
数据处理指令:数学运算,逻辑运算 立即数 立即数的本质 就是包含在指令当中的数,属于指令的一部分 立即数的优点:取指的时候就可以将其读取到CPU,不用单独去内存读取,速度快 立即数的缺点:不…...
Excel embed into a webpage
无法编辑嵌入式 Excel 网页版 工作簿,但具有适当权限的人员可能能够在 Excel 中打开嵌入的工作簿,他们可以在其中编辑数据。 通过制作一个浏览器,打开并编辑它 https://onedrive.live.com/embed? resid5FC97855340825A9%21135& aut…...

uniapp点击事件在小程序中无法传参
这个问题很是神奇,第一次遇到。在h5中,点击事件可以正常传参,打包小程序后确失效了。 修改:for循环中的key,使用 index就好了...

ssprompt:一个LLM Prompt分发管理工具
阅读顺序 🌟前言🔔ssprompt介绍命令介绍Metafile介绍版本依赖规则 🌊 PromptHubGitHub Token 🚀 Quick Install系统依赖pip安装Linux, macOS, Windows (WSL)Windows (Powershell) 🚩 Roadmap🌏 项目交流讨论…...

修复 ChatGPT 发生错误的问题
目录 ChatGPT 发生错误?请参阅如何修复连接错误! 修复 ChatGPT 发生错误的问题 基本故障排除技巧 检查 ChatGPT 的服务器状态 检查 API 限制 检查输入格式 清除浏览数据 香港DSE是什么? 台湾指考是什么? 王湘浩 生平 …...

《热题100》字符串、双指针、贪心算法篇
思路:对于输入的的字符串,只有三种可能,ipv4,ipv6,和neither ipv4:四位,十进制,无前导0,小于256 ipv6:八位,十六进制,无多余0(00情况不允许),不…...

大数据组件Sqoop-安装与验证
🥇🥇【大数据学习记录篇】-持续更新中~🥇🥇 个人主页:beixi 本文章收录于专栏(点击传送):【大数据学习】 💓💓持续更新中,感谢各位前辈朋友们支持…...

运算符重载(个人学习笔记黑马学习)
1、加号运算符重载 #include <iostream> using namespace std; #include <string>//加号运算符重载 class Person { public://1、成员函数重载号//Person operator(Person& p) {// Person temp;// temp.m_A this->m_A p.m_A;// temp.m_B this->m_B p…...

2023.9.6 Redis 的基本介绍
目录 Redis 的介绍 Redis 用作缓存和存储 session 信息 Redis 用作数据库 消息队列 消息队列是什么? Redis 用作消息队列 Redis 的介绍 特点: 内存中存储数据:奠定了 Redis 进行访问和存储时的快可编程性:支持使用 Lua 编写脚…...
2023-09-08力扣每日一题
链接: 2651. 计算列车到站时间 题意: 不看日期只看时间 解: ? 实际代码: 还看!你怎么肥四?int findDelayedArrivalTime(int arrivalTime, int delayedTime) {return (arrivalTimedelayed…...

adb-linux 调试桥
这里写自定义目录标题 摘要:一、简介二、adb使用参考连接 摘要: adb 可替代网络、串口等调试手段,可以方便的进行文件传输、终端登录等 一、简介 ADB的全称为Android Debug Bridge,即调试桥,方便调试设备或调试开发…...

入门人工智能 —— 使用 Python 进行文件读写,并完成日志记录功能(4)
入门人工智能 —— 使用 Python 进行文件读写(4) 入门人工智能 —— 使用 Python 进行文件读写打开文件读取文件内容读取整个文件逐行读取文件内容读取所有行并存储为列表 写入文件内容关闭文件 日志记录功能核心代码:完整代码:运…...

使用Caffeine实现帖子的缓存来优化网站的运行速度
导入依赖 <!-- https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine --><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.1.7</version>…...
Webpack5 搭建Vue项目(进阶版)
Webpack5 搭建Vue项目(进阶版) 提示:中间隔了好长时间,我胡汉三又回来继续更新了!!!😂😂😂 文章目录 Webpack5 搭建Vue项目(进阶版)前…...

论文阅读:Distortion-Free Wide-Angle Portraits on Camera Phones
论文阅读:Distortion-Free Wide-Angle Portraits on Camera Phones 今天介绍一篇谷歌 2019 年的论文,是关于广角畸变校正的。 Abstract 广角摄影,可以带来不一样的摄影体验,因为广角的 FOV 更大,所以能将更多的内容…...

力扣每日一题---207. 课程表
Problem: 207. 课程表 文章目录 解题方法复杂度Code 解题方法 y总的 Topsort 模板题 复杂度 时间复杂度: 添加时间复杂度, 示例: O ( n ) O(n) O(n) 空间复杂度: 添加空间复杂度, 示例: O ( n ) O(n) O(n) Code class Solution {int res 0; public…...
在Kubernetes环境中有关Nginx Ingress与API Gateway的连接问题
文章目录 小结问题解决参考 小结 在Kubernetes环境中是通过Nginx Ingress来从外部访问Kubernetes内部的环境,并用API Gateway来分发请求,碰到了 502 Bad gateway.的问题,并尝试解决。 问题 从外部通过Nginx Ingress访问Kubernetes内部的环…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...