Android 开发 Camera类的拍照与录像
前言
在开发Android应用的时候,如果需要调用摄像头拍照或者录像,除了通过Intent调用系统现有相机应用进行拍照录像之外,还可以通过直接调用Camera硬件去去获取摄像头进行拍照录像的操作。本篇博客将讲解如何在Android应用中通过Camera拍照功能.
录像功能因为需要与MediaRecorder配使用,反而是更偏向操作MediaRecorder,所以我把录像功能放到了音视频开发篇幅里,请参考以下博客了解录像功能开发.
MediaRecorder视频录制入门:https://www.cnblogs.com/guanxinjing/p/10980906.html
MediaRecorder与Camera1配合使用:https://www.cnblogs.com/guanxinjing/p/10986766.html
拍照开发
流程
- 获取权限
- 初始化曲面视图View(SurfaceView或者TextureView)(用于显示相机预览图像)
- 初始化打开相机,选择前后摄像头
- 配置相机参数
- 拍照
- 处理照片返回数据,旋转照片与压缩照片
获取权限
<!-- 相机相关 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
拍照TextureView例子
其实目前最适合相机预览图像显示使用的是TextureView,因为它是真正独立刷新帧数的View,可以让相机预览减少卡顿问题
而使用TextureView需要开启硬件加速功能.开启硬件加速方法如下:
在AndroidManifest.xml 清单文件里,你需要实现相机功能的activity添加 android:hardwareAccelerated="true"
<activity android:name=".work.share.FaceCameraActivity"
android:hardwareAccelerated="true"></activity>
以下是代码部分:
public class FaceCameraActivity extends BaseActivity implements TextureView.SurfaceTextureListener,Camera.PictureCallback , View.OnClickListener{
private static final float PICTURE_SIZE_PROPORTION = 1.1f;//目标分辨率尺寸
private TextureView mTextureView;
private Camera mCamera;
private Button mBtnCamera;
private boolean mMoveTakingPhotos = false; //用于防止连续点击拍照多次引起报错的问题 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initCamera();
initCameraParameters(); } @Override
public int getLayout() {
return R.layout.activity_face_camera;
} @Override
public void initView() {
mTextureView = findViewById(R.id.texture_view);
mBtnCamera = findViewById(R.id.btn_camera);
mBtnCamera.setOnClickListener(this);
mTextureView.setSurfaceTextureListener(this);//添加监听,用于监听TextureView的创建/变化/销毁 } @Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_camera:
if(!mMoveTakingPhotos){
mMoveTakingPhotos = true;
mCamera.takePicture(null,null,this);//拍摄拍照 参数为快门图片回调/原始图片回调(未压缩)/jpeg图片回调
}
break;
default:
break;
} } /**
* 初始化打开相机
*/
private void initCamera(){
if (mCamera == null){
//大多数情况下:0是后置摄像头 1是前置摄像头 ,这里demo就不弄这么复杂,在下面的会提供选择前后摄像头的方法
mCamera = Camera.open(1); } } /**
* 初始化相机参数
*/
private void initCameraParameters(){
Camera.Parameters parameters = mCamera.getParameters();
// parameters.getPreviewSize();//当前预览尺寸
// parameters.getPictureSize();//当前分辨率尺寸
// parameters.getJpegThumbnailSize(); //返回当前jpeg图片中exif缩略图的尺寸 // parameters.getSupportedPreviewSizes();//预览尺寸List
// parameters.getSupportedPictureSizes();//分辨率尺寸List
// parameters.getSupportedJpegThumbnailSizes();//返回当前jpeg图片中exif缩略图的尺寸List DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
Camera.Size previewSize = getpreviewSize(parameters, displayMetrics.heightPixels, displayMetrics.widthPixels);//获取最接近屏幕分辨率的的预览尺寸
Camera.Size pictureSize = getPictureSize(parameters, PICTURE_SIZE_PROPORTION);//获取对应比例的最大分辨率
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);//设置关闭闪光灯
parameters.setFocusMode(Camera.Parameters.FLASH_MODE_AUTO); //对焦设置为自动
parameters.setPictureFormat(PixelFormat.JPEG);//拍照格式
parameters.setPreviewSize(previewSize.width, previewSize.height);//设置预览尺寸
parameters.setPictureSize(pictureSize.width, pictureSize.height);//分辨率尺寸
parameters.set("orientation", "portrait");//相片方向
parameters.set("rotation", 90); //相片镜头角度转90度(默认摄像头是横拍)
mCamera.setParameters(parameters);//添加参数
mCamera.setDisplayOrientation(90);//设置显示方向
} /**
* 计算获得最接近比例的预览尺寸
* @param parameters
* @param height
* @param width
* @return
*/
private Camera.Size getpreviewSize(Camera.Parameters parameters, int height, int width){
List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
Camera.Size selectPreviewSize = null; //缓存当前最准确比例的Size
float currentDifference = 0; //缓存当前最小的差值
/**
* 下面这行代码是求传入高度和宽度的高宽比例,这里可以发现一个细节我下面的预览尺寸求的的宽高比例.
* 是的他们一个是高宽比一个是宽高比,说明为什么这样,因为如果按照2个都是高宽比来获得预览尺寸你会发现,获得的尺寸怎么都有可能会拉伸变形(除非狗屎运尺寸完美刚好)
* 最好的办法就是,不求最合适目标尺寸的长方形比例,而求一个最适合目标尺寸的正方形比例,这样拉伸变形就不会出现了
*/
float proportion = (float)height/(float)width;
for (int i = 0; i < previewSizeList.size(); i++){
Camera.Size size = previewSizeList.get(i);
float previewSizeProportion = ((float)size.width)/((float)size.height); //计算当前预览尺寸的宽高比例
float tempDifference = Math.abs(previewSizeProportion - proportion); //相减求绝对值的差值
if(i == 0){
selectPreviewSize = size;
currentDifference = tempDifference;
continue;
}
if (tempDifference <= currentDifference){ //获得最小差值
if (tempDifference == currentDifference){ //如果差值一样
if ((selectPreviewSize.width + selectPreviewSize.height) < (size.width+size.height)){ //判断那个尺寸大保留那个
selectPreviewSize = size;
currentDifference = tempDifference;
} }else { //如果差值更小更准确
selectPreviewSize = size;
currentDifference = tempDifference;
}
}
L.e("currentDifference="+currentDifference +"width="+selectPreviewSize.width+"height="+selectPreviewSize.height); }
return selectPreviewSize;
} /**
* 计算获得最接近比例的分辨率
* @param parameters
* @param targetProportion
* @return
*/
private Camera.Size getPictureSize(Camera.Parameters parameters, float targetProportion) {
List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
Camera.Size selectPreviewSize = null;
float currentDifference = 0;
for (int i = 0; i < pictureSizeList.size(); i++) {
Camera.Size size = pictureSizeList.get(i);
L.e("分辨率列表_" + i + "_width=" + size.width + "height=" + size.height);
float pictureSizeProportion = ((float) size.width) / ((float) size.height);
L.e("分辨率列表_" + i + "_比例=" + pictureSizeProportion);
float tempDifference = Math.abs(pictureSizeProportion - targetProportion);
if (i == 0) {
selectPreviewSize = size;
currentDifference = tempDifference;
continue;
}
if (tempDifference <= currentDifference) {
if (tempDifference == currentDifference) {
if ((selectPreviewSize.width + selectPreviewSize.height) < (size.width + size.height)) { //判断那个尺寸大保留那个
selectPreviewSize = size;
currentDifference = tempDifference;
}
} else { //如果差值更小更准确
selectPreviewSize = size;
currentDifference = tempDifference; }
} }
L.e("当前选择分辨率width=" + selectPreviewSize.width + "height=" + selectPreviewSize.height);
return selectPreviewSize;
} /**
* 照片拍照完成后的回调方法
* @param data
* @param camera
*/
@Override
public void onPictureTaken(final byte[] data, Camera camera) {
//注意!此处返回是主线程,而处理图片是耗时操作需要放到子线程里处理
handlerImageWaitDialog().show();
new Thread(new Runnable() {
@Override
public void run() {
try {
//这里有一个坑,如果你想要读取照片的角度信息,那么就需要直接吧byte[] data的照片数据先保存成图片文件在从文件读成Bitmap
//因为如果你先处理压缩图片或者裁剪图片,只要是Bitmap.createBitmap处理过就都有可能丢失这些照片信息到时候你怎么获取角度都是0
FilePathSession.deleteFaceImageFile();
FileOutputStream fileOutputStream = new FileOutputStream(FilePathSession.getFaceImagePath());
fileOutputStream.write(data,0,data.length);
fileOutputStream.flush();
fileOutputStream.close();
int angle = readPictureDegree(FilePathSession.getFaceImagePath().toString()); //获取角度
Bitmap bitmap = BitmapFactory.decodeFile(FilePathSession.getFaceImagePath().toString());//重新在文件里获取图片
Matrix matrix = new Matrix();//创建矩阵配置类,用与设置旋转角度和旋转位置
matrix.setRotate(angle, bitmap.getWidth(), bitmap.getHeight());//设置旋转角度和旋转位置
Bitmap handlerAngleBitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
ImageHandle.bitmapImageConfig(handlerAngleBitmap)//这个是个人写的压缩图片工具类
.setTargetKB(200)
.setSize(1080f,1920f)
.setHandleListener(new BitmapImageHandleListener() {
@Override
public boolean onReady(Bitmap inpBitmap) {
return true;
} @Override
public void onSuccess(Bitmap outBitmap) {
try {
FileOutputStream fileOutputStream = new FileOutputStream(FilePathSession.getFaceImagePath());
outBitmap.compress(Bitmap.CompressFormat.JPEG,90,fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
outBitmap.recycle();
runOnUiThread(new Runnable() {
@Override
public void run() {
handlerImageWaitDialog().dismiss();
Intent startFaceConfirm = new Intent(FaceCameraActivity.this, FaceConfirmActivity.class);
startActivity(startFaceConfirm);
FaceCameraActivity.this.finish(); }
});
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
mMoveTakingPhotos = false;
handlerImageWaitDialog().dismiss();
Toast.makeText(FaceCameraActivity.this, "图像压缩处理失败", Toast.LENGTH_SHORT).show();
}
});
} } @Override
public void onFailure(String text) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mMoveTakingPhotos = false;
handlerImageWaitDialog().dismiss();
Toast.makeText(FaceCameraActivity.this, "图像压缩处理失败", Toast.LENGTH_SHORT).show();
}
}); } @Override
public void onError(Exception e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mMoveTakingPhotos = false;
handlerImageWaitDialog().dismiss();
Toast.makeText(FaceCameraActivity.this, "图像压缩处理失败", Toast.LENGTH_SHORT).show();
}
}); }
}).build(); } catch (FileNotFoundException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
mMoveTakingPhotos = false;
handlerImageWaitDialog().dismiss();
Toast.makeText(FaceCameraActivity.this, "图像压缩处理失败", Toast.LENGTH_SHORT).show();
}
});
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
mMoveTakingPhotos = false;
handlerImageWaitDialog().dismiss();
Toast.makeText(FaceCameraActivity.this, "图像压缩处理失败", Toast.LENGTH_SHORT).show();
}
});
}
}
}).start(); } /**
* TextureView的创建完成后的可用状态回调
*/
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
//可用
try {
mCamera.setPreviewTexture(surface);//给相机添加预览图像的曲面View
mCamera.startPreview();//启动图像预览
} catch (IOException e) {
e.printStackTrace();
} } @Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
//尺寸变化 } @Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
//销毁
return false;
} @Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
//更新 } /**
* 读取照片旋转角度
*
* @param path 照片路径
* @return 角度
*/
public int readPictureDegree(String path) {
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
L.e("触发 90度");
degree = 90;
degree = degree + 90;//这里我是直接处理要增加或者减少的角度,让图片竖起来
break;
case ExifInterface.ORIENTATION_ROTATE_180:
L.e("触发 180度");
degree = 180;
degree = degree + 0;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
L.e("触发 270度");
degree = 270;
degree = degree - 90;
break;
default:
L.e("触发 0度");
degree = 0;
degree = degree + 180;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return degree;
} @Override
protected void onResume() {
super.onResume();
// try {
// mCamera.reconnect(); //相机重连接
// mCamera.startPreview();
// } catch (IOException e) {
// e.printStackTrace();
// }
} @Override
protected void onStop() {
super.onStop();
// mCamera.stopPreview();暂停预览
} @Override
protected void onDestroy() {
super.onDestroy();
if (mCamera != null){
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
选择前后摄像头的代码
/**
* 选择摄像头
* @param isFacing true=前摄像头 false=后摄像头
* @return 摄像id
*/
private Integer selectCamera(boolean isFacing){
int cameraCount = Camera.getNumberOfCameras();
// CameraInfo.CAMERA_FACING_BACK 后摄像头
// CameraInfo.CAMERA_FACING_FRONT 前摄像头
int facing = isFacing ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK;
Log.e(TAG, "selectCamera: cameraCount="+cameraCount);
if (cameraCount == 0){
Log.e(TAG, "selectCamera: The device does not have a camera ");
return null;
}
Camera.CameraInfo info = new Camera.CameraInfo();
for (int i=0; i < cameraCount; i++){
Camera.getCameraInfo(i,info);
if (info.facing == facing){
return i;
} }
return null; }
如果你需要切换摄像头
mCamera.stopPreview();//暂停预览
mCamera.release();//释放摄像头 这个是关键
openCamera(selectCamera(mCurrentCameraFacing));//重新选择摄像头并且打开
configCameraParameters();//重新配置摄像头参数
startPreview(mSurfaceTexture);//开启预览
拍照SurfaceView例子
package com.demo; import androidx.appcompat.app.AppCompatActivity; import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button; import com.example.user.demo.R; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; public class TakePictureActivity extends AppCompatActivity implements SurfaceHolder.Callback,Camera.PictureCallback {
private static final String TAG = "TakePictureActivity";
private Button mBtnTake;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private Camera mCamera; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_take_picture);
mBtnTake = (Button)findViewById(R.id.take);
mSurfaceView = (SurfaceView)findViewById(R.id.surfaceView);
init();
mBtnTake.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mCamera != null){
mCamera.takePicture(null,null,TakePictureActivity.this);
}
}
}); } @Override
protected void onDestroy() {
super.onDestroy();
mSurfaceHolder.removeCallback(this);
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release(); } private void init(){
mSurfaceHolder = mSurfaceView.getHolder();
mCamera = Camera.open();
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mSurfaceHolder.addCallback(this);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode("off");
parameters.setPictureFormat(PixelFormat.JPEG); //设定相片格式为JPEG,默认为NV21
parameters.setPreviewSize(640, 480);
parameters.set("orientation", "portrait");//相片方向
parameters.set("rotation", 90); //相片镜头角度转90度(默认摄像头是横拍)
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
} @Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e(TAG,"悬浮窗口生成");
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
} } @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e(TAG,"悬浮窗口变化"); } @Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG,"悬浮窗口销毁"); } @Override
public void onPictureTaken(final byte[] data, Camera camera) {
Log.e(TAG,"拍照结果处理");
File file = getExternalFilesDir("takePiceture");
if (!file.exists()){
file.mkdirs();
}
final File fileName = new File(file,System.currentTimeMillis()+".jpg");
new Thread(new Runnable() {
@Override
public void run() {
try {
FileOutputStream fileOutputStream = new FileOutputStream(fileName);
fileOutputStream.write(data);
fileOutputStream.close();
mCamera.startPreview();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} }
Camera api 说明
Camera是Android摄像头硬件的相机类,位于硬件包"android.hardware.Camera"下。它主要用于摄像头捕获图片、启动/停止预览图片、拍照、获取视频帧等,它是设备本地的服务,负责管理设备上的摄像头硬件。
Camera既然用于管理设备上的摄像头硬件,那么它也为开发人员提供了相应的方法,并且这些方法大部分都是native的,用C++在底层实现,下面简单介绍一下Camera的一些方法:
api | 说明 |
open() | 打开Camera,返回一个Camera实例。 |
open(int cameraId) | 根据cameraId打开一个Camera,返回一个Camera实例。 |
release() | 释放掉Camera的资源。 |
getNumberOfCameras() | 获取当前设备支持的Camera硬件个数。 |
getParameters() | 获取Camera的各项参数设置类。 |
setParameters(Camera.Parameters params) | 通过params把Camera的各项参数写入到Camera中。 |
setDisplayOrientation(int degrees) | 摄像预览的旋转度。 |
setPreviewDisplay(SurfaceHolder holder) | 设置Camera预览的SurfaceHolder。 |
starPreview() | 开始Camera的预览。 |
stopPreview() | 停止Camera的预览 |
setPreviewCallback() | 设置预览回调 |
reconnect() | 重新连接 |
autoFocus(Camera.AutoFocusCallback cb) | 自动对焦 |
cancelAutoFocus() | 取消启动对焦 |
setAutoFocusMoveCallback() | 自动对焦移动回调 |
takePicture(Camera.ShutterCallback shutter,Camera.PictureCallback raw,Camera.PictureCallback jpeg) | 拍照。 |
enableShutterSound() | 启用快门声音 |
lock() | 锁定Camera硬件,使其他应用无法访问。 |
unlock() | 解锁Camera硬件,使其他应用可以访问。 |
startFaceDetection() | 启动人脸识别 |
stopFaceDetection() | 停止人脸识别 |
setFaceDetectionListener() | 人脸识别监听回调 |
setPreviewCallback() | 设置预览回调 |
setPreviewCallbackWithBuffer() | 设置预览缓冲回调 |
setOneShotPreviewCallback() | 设置一个镜头预览回调 |
setErrorCallback() | 设置异常回调 |
startSmoothZoom() | 启动平滑缩放 |
stopSmoothZoom() | 停止平滑缩放 |
setZoomChangeListener() | 缩放监听 |
setPreviewTexture() | 设置预览纹理 |
上面已经介绍了Camera的常用方法,下面根据这些方法详细讲解Android下使用Camera开发拍照应用最基本的过程:
- 使用open()方法获取一个Camera对象,鉴于Android设备可能配置了多个摄像头,open()方法可以通过摄像头Id开启指定的摄像头。
- 为Camera对象设置预览类,它是一个SurfaceHolder对象,通过setPreviewDisplay(SurfaceHolder)方法设置。
- 调用startPreview()方法开始Camera对象的预览。
- 调用takePicture()方法进行拍照,其中可以通过Camera.PictureCallback()回调获得拍摄的Image数据。
- 当拍摄完成后,需要调用stopPreview()方法停止预览,并使用release()释放Camera占用的资源。
Android 开发 Camera类的拍照与录像的更多相关文章
- android.hardware.Camera类及其标准接口介绍
android.hardware.Camera类及其标准接口介绍,API level 19 http://developer.android.com/reference/android/hardwar ...
- Android开发之控制摄像头拍照
如今的手机一般都会提供相机功能,有些相机的镜头甚至支持1300万以上像素,有些甚至支持独立对焦.光学变焦这些仅仅有单反才有的功能,甚至有些手机直接宣传能够拍到星星.能够说手机已经变成了专业数码相机.为 ...
- Android开发——Context类的各种细节问题
0. 前言 Context相信所有的Android开发人员基本上每天都在接触,因为它太常见了.但实际上Context有太多小的细节并不被大家所关注,那么今天我们就来学习一下那些你所不知道的细节. ...
- Android 开发工具类 35_PatchUtils
增量更新工具类[https://github.com/cundong/SmartAppUpdates] import java.io.File; import android.app.Activity ...
- Android开发之裁切(拍照+相冊)图像并设置头像小结
先看效果: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5 ...
- Android开发工具类
7种无须编程的DIY开发工具 你知道几个? 现如今,各种DIY开发工具不断的出现,使得企业和个人在短短几分钟内就能完成应用的创建和发布,大大节省了在时间和资金上的投入.此外,DIY工 具的出现,也帮助 ...
- android开发工具类之获得WIFI IP地址或者手机网络IP
有的时候我们需要获得WIFI的IP地址获得手机网络的IP地址,这是一个工具类,专门解决这个问题,这里需要两个权限: <uses-permission android:name="and ...
- android开发工具类总结(一)
一.日志工具类 Log.java public class L { private L() { /* 不可被实例化 */ throw new UnsupportedOperationException ...
- Android 开发工具类 19_NetworkStateReceiver
检测网络状态改变类: 1.注册网络状态广播: 2.检查网络状态: 3.注销网络状态广播: 4.获取当前网络状态,true为网络连接成功,否则网络连接失败: 5.注册网络连接观察者: 6.注销网络连接观 ...
随机推荐
- 修改oracle数据库内存报错
今天修改oracle数据库内存时, alter system set memory_max_target=10240M scope=spfile;语句正确修改:但重启时却报错 : SQL> al ...
- 常用socket选项
1.socket选项通常:服务端应在listen 前设置,accpet返回的socket继承自监听套接字. 客户端应在connect之前设置 2.socket 如果有大量短连接应设置SO_LINGER ...
- 自建yum仓库,分别为网络源和本地源
配置本地源 建立本地源目录 [root@qingcheng-db lgp]#mkdir /mnt/cdrom [root@qingcheng-db lgp]#mkdir /yum 挂载Centos光盘 ...
- 爬虫模块介绍--Beautifulsoup (解析库模块,正则)
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时 ...
- Linux可以生产uImage
默认kernel只生产Image和zImage,若想让kernel生产uImage,需要用到mkimage,这个是uboot可以提供的,位于uboot/tool/目录下,将其加入到环境变量即可.
- 学习笔记CB011:lucene搜索引擎库、IKAnalyzer中文切词工具、检索服务、查询索引、导流、word2vec
影视剧字幕聊天语料库特点,把影视剧说话内容一句一句以回车换行罗列三千多万条中国话,相邻第二句很可能是第一句最好回答.一个问句有很多种回答,可以根据相关程度以及历史聊天记录所有回答排序,找到最优,是一个 ...
- vim 常用 NERDTree 快捷键
ctrl + w + h 光标 focus 左侧树形目录 ctrl + w + l 光标 focus 右侧文件显示窗口 ctrl + w + w 光标自动在左右侧窗口切换 ctrl + w + r 移 ...
- java web(六):mybatis之一对一、一对多、多对多映射
前言: 百度百科: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可 ...
- opendistro 试用
以前转载过一篇别人的关于opendistro的文章,还好使用docker-compose 运行,很方便,所以自己也跑下 环境准备 docker-compose 文件 version: '3' serv ...
- Devexpress之LayoutControl的使用及其控件布局设计
引言 Devexpress给我们提供了更加美观.更加丰富控件,但在学习和使用的同时经常会遇到诸多麻烦.今天在使用Devexpress的LayoutControl控件进行界面控件的布局设计时遇到了如下的 ...